<template>
  <div class="writer-container">
    <!-- 顶部标题栏 -->
    <div class="title-bar">
      <div class="title-left">
        <el-button @click="goBack" size="small">
          <el-icon><ArrowLeft /></el-icon>
          返回列表
        </el-button>
        <span class="novel-title">{{ currentNovel?.title || '小说编辑' }}</span>
      </div>
    </div>

    <!-- 主要内容区域 -->
    <div class="main-content" v-loading="pageLoading" element-loading-text="正在加载小说数据...">
      <!-- 左侧面板 -->
      <div class="left-panel">
        <!-- 章节列表面板 -->
        <ChapterListPanel
          v-show="activeTab === 'editor'"
          :chapters="chapters"
          :current-chapter="currentChapter"
          :loading="chaptersLoading"
          :pagination="chapterPagination"
          @select-chapter="selectChapter"
          @chapter-command="handleChapterCommand"
          @chapter-action="handleChapterAction"
          @add-new-chapter="addNewChapter"
          @page-change="handleChapterPageChange"
          @size-change="handleChapterSizeChange"
        />

        <!-- 人物管理面板 -->
        <CharacterListPanel
          v-show="activeTab === 'characters'"
          :characters="characters"
          :loading="charactersLoading"
          :novel-id="currentNovel?.id"
          :check-api-and-balance="checkApiAndBalance"
          :novel-info="currentNovel"
          @update:characters="characters = $event"
        />

        <!-- 世界观管理面板 -->
        <WorldviewListPanel
          v-show="activeTab === 'worldview'"
          :world-settings="worldSettings"
          :loading="worldSettingsLoading"
          @add-world-setting="addWorldSetting"
          @edit-world-setting="editWorldSetting"
          @world-setting-action="handleWorldSettingAction"
          @open-world-generate-dialog="openWorldGenerateDialog"
        />

        <!-- 语料库面板 -->
        <CorpusListPanel
          v-show="activeTab === 'corpus'"
          :corpus-data="corpusData"
          :loading="corpusLoading"
          @add-corpus="addCorpus"
          @edit-corpus="editCorpus"
          @delete-corpus="deleteCorpus"
        />

        <!-- 事件线面板 -->
        <EventTimelinePanel
          v-show="activeTab === 'events'"
          :events="events"
          :loading="eventsLoading"
          @add-event="addEvent"
          @event-action="handleEventAction"
        />
      </div>

      <!-- 右侧编辑器区域 -->
      <div class="editor-panel">
        <div v-if="currentChapter" class="editor-content">
          <div class="editor-header">
            <div class="editor-header-left">
              <h3 class="chapter-title">✍️ {{ currentChapter.title }}</h3>
              <div class="chapter-meta">
                <span class="word-count">{{ contentWordCount }}字</span>
                <el-select
                    v-model="currentChapter.status"
                    size="small"
                    style="width: 80px;"
                    @change="updateChapterStatus"
                    popper-class="chapter-status-dropdown"
                >
                  <el-option label="草稿" value="draft" />
                  <el-option label="完成" value="completed" />
                  <el-option label="发表" value="published" />
                </el-select>
                <span v-if="isSaving" class="saving-indicator">● 保存中...</span>
              </div>
            </div>
            <div class="editor-header-right">
              <el-button-group>
                <el-button size="small" @click="generateFromOutline" :disabled="!currentChapter.description">
                  <el-icon><Star /></el-icon>
                  根据大纲生成
                </el-button>
                <el-button size="small" @click="openContinueDialog">
                  <el-icon><ArrowRight /></el-icon>
                  续写
                </el-button>
                <el-button size="small" @click="enhanceContent">
                  <el-icon><Tools /></el-icon>
                  优化
                </el-button>
              </el-button-group>
            </div>
          </div>


          <div class="editor-container">
            <div class="editor-wrapper">
              <QuillEditor
                  ref="editorRef"
                  v-model="content"
                  placeholder="开始您的创作..."
                  @change="onContentChange"
                  @ready="handleEditorReady"
              />
            </div>
          </div>
        </div>

        <!-- 章节编辑对话框 -->
        <el-dialog v-model="showChapterDialog" :title="editingChapter ? '编辑章节' : '新增章节'" width="600px">
          <el-form :model="chapterForm" label-width="80px">
            <el-form-item label="章节标题">
              <el-input v-model="chapterForm.title" placeholder="请输入章节标题" />
            </el-form-item>
            <el-form-item label="章节简介">
              <div class="chapter-description-wrapper">
                <el-input
                    v-model="chapterForm.description"
                    type="textarea"
                    :rows="6"
                    placeholder="简要描述本章节内容..."
                    class="description-textarea"
                />
                <el-button
                    size="small"
                    type="primary"
                    @click="generateChapterOutline"
                    :loading="isGeneratingOutline"
                    class="ai-generate-btn"
                    plain
                >
                  <el-icon><Star /></el-icon>
                  <span>AI生成</span>
                </el-button>
              </div>
            </el-form-item>
            <el-form-item label="章节状态">
              <el-select v-model="chapterForm.status">
                <el-option label="草稿" value="draft" />
                <el-option label="完成" value="completed" />
                <el-option label="发表" value="published" />
              </el-select>
            </el-form-item>
          </el-form>
          <template #footer>
            <el-button @click="showChapterDialog = false">取消</el-button>
            <el-button type="primary" @click="saveChapter">确定</el-button>
          </template>
        </el-dialog>

        <!-- 世界观编辑对话框 -->
        <el-dialog v-model="showWorldDialog" title="编辑世界观设定" width="600px">
          <el-form :model="worldForm" label-width="80px">
            <el-form-item label="设定标题">
              <el-input v-model="worldForm.title" />
            </el-form-item>
            <el-form-item label="类别">
              <el-select v-model="worldForm.category">
                <el-option label="世界设定" value="setting" />
                <el-option label="魔法体系" value="magic" />
                <el-option label="政治势力" value="politics" />
                <el-option label="地理环境" value="geography" />
                <el-option label="历史背景" value="history" />
              </el-select>
            </el-form-item>
            <el-form-item label="详细描述">
              <div class="form-item-with-ai">
                <el-input v-model="worldForm.description" type="textarea" :rows="6" />
                <el-button
                    size="small"
                    type="primary"
                    @click="generateWorldSettingAI"
                    :loading="isGeneratingWorldSetting"
                    style="margin-top: 8px;"
                >
                  <el-icon><Star /></el-icon>
                  AI生成描述
                </el-button>
              </div>
            </el-form-item>
          </el-form>

          <!-- 流式生成状态显示 -->
          <div v-if="isStreaming && streamingType === 'worldSetting'" class="streaming-status-card">
            <div class="streaming-header">
              <span class="streaming-title">🤖 AI正在生成世界观设定...</span>
            </div>
            <div class="streaming-content-display" v-html="formatStreamingContent(streamingContent)"></div>
          </div>

          <template #footer>
            <el-button @click="showWorldDialog = false">取消</el-button>
            <el-button type="primary" @click="saveWorldSetting">保存</el-button>
          </template>
        </el-dialog>

        <!-- 语料库编辑对话框 -->
        <el-dialog v-model="showCorpusDialog" title="编辑语料" width="700px">
          <el-form :model="corpusForm" label-width="80px">
            <el-form-item label="标题">
              <el-input v-model="corpusForm.title" />
            </el-form-item>
            <el-form-item label="类型">
              <el-select v-model="corpusForm.type">
                <el-option label="场景描述" value="description" />
                <el-option label="对话模板" value="dialogue" />
                <el-option label="情感表达" value="emotion" />
                <el-option label="动作描写" value="action" />
                <el-option label="心理描写" value="psychology" />
              </el-select>
            </el-form-item>
            <el-form-item label="内容">
              <el-input v-model="corpusForm.content" type="textarea" :rows="8" />
            </el-form-item>
          </el-form>
          <template #footer>
            <el-button @click="showCorpusDialog = false">取消</el-button>
            <el-button type="primary" @click="saveCorpus">保存</el-button>
          </template>
        </el-dialog>

        <!-- 事件编辑对话框 -->
        <el-dialog v-model="showEventDialog" title="编辑事件" width="600px">
          <el-form :model="eventForm" label-width="80px">
            <el-form-item label="事件标题">
              <el-input v-model="eventForm.title" />
            </el-form-item>
            <el-form-item label="相关章节">
              <el-select v-model="eventForm.chapter" placeholder="选择章节">
                <el-option
                    v-for="chapter in chapters"
                    :key="chapter.id"
                    :label="chapter.title"
                    :value="chapter.title"
                />
              </el-select>
            </el-form-item>
            <el-form-item label="时间线">
              <el-input v-model="eventForm.time" placeholder="如：第三天傍晚" />
            </el-form-item>
            <el-form-item label="重要程度">
              <el-radio-group v-model="eventForm.importance">
                <el-radio label="low">次要</el-radio>
                <el-radio label="normal">一般</el-radio>
                <el-radio label="high">重要</el-radio>
                <el-radio label="critical">关键</el-radio>
              </el-radio-group>
            </el-form-item>
            <el-form-item label="事件描述">
              <el-input v-model="eventForm.description" type="textarea" :rows="4" />
            </el-form-item>
          </el-form>
          <template #footer>
            <el-button @click="showEventDialog = false">取消</el-button>
            <el-button type="primary" @click="saveEvent">保存</el-button>
          </template>
        </el-dialog>
           <!-- 用以下代码替换 el-dialog -->
   <ChapterGenerateDialog
     v-model="showChapterGenerateDialog"
     :current-chapter="currentChapter"
     :current-novel="currentNovel"
     :characters="characters"
     :world-settings="worldSettings"
     :corpus-data="corpusData"
     :events="events"
     :chapters="chapters"
     :available-prompts="availablePrompts"
     :is-generating-content="isGeneratingContent"
     @generate="handleChapterGenerate"
   />
        <!-- 世界观AI生成对话框 -->
        <el-dialog v-model="showWorldGenerateDialog" title="AI生成世界观设定" width="800px" @close="showWorldGenerateDialog = false">
          <div class="world-generate-content">
            <!-- 配置区域 -->
            <el-card v-if="!worldGenerating && generatedWorldSettings.length === 0" shadow="never" class="config-section">
              <template #header>
                <span>⚙️ 生成配置</span>
              </template>

              <el-form label-width="120px" size="default">
                <el-form-item label="生成数量">
                  <el-input-number v-model="worldGenerateConfig.count" :min="1" :max="8" />
                </el-form-item>

                <el-form-item label="设定类型">
                  <div class="world-type-options">
                    <el-checkbox v-model="worldGenerateConfig.includeGeography">地理环境</el-checkbox>
                    <el-checkbox v-model="worldGenerateConfig.includeCulture">文化社会</el-checkbox>
                    <el-checkbox v-model="worldGenerateConfig.includeHistory">历史背景</el-checkbox>
                    <el-checkbox v-model="worldGenerateConfig.includeMagic">魔法体系</el-checkbox>
                    <el-checkbox v-model="worldGenerateConfig.includeTechnology">科技水平</el-checkbox>
                    <el-checkbox v-model="worldGenerateConfig.includePolitics">政治势力</el-checkbox>
                    <el-checkbox v-model="worldGenerateConfig.includeReligion">宗教信仰</el-checkbox>
                    <el-checkbox v-model="worldGenerateConfig.includeEconomy">经济贸易</el-checkbox>
                    <el-checkbox v-model="worldGenerateConfig.includeRaces">种族设定</el-checkbox>
                    <el-checkbox v-model="worldGenerateConfig.includeLanguage">语言文字</el-checkbox>
                  </div>
                </el-form-item>

                <!-- 提示词选择 -->
                <el-form-item label="使用提示词">
                  <div style="display: flex; gap: 10px; align-items: center;">
                    <el-button
                        type="primary"
                        plain
                        size="small"
                        @click="openWorldSettingPromptSelector"
                    >
                      📝 选择提示词
                    </el-button>
                    <span v-if="worldSettingSelectedPrompt" class="selected-prompt-info">
                  已选择：{{ worldSettingSelectedPrompt.title }}
                </span>
                    <el-button
                        v-if="worldSettingSelectedPrompt"
                        link
                        size="small"
                        type="danger"
                        @click="clearWorldSettingPrompt"
                    >
                      清除
                    </el-button>
                  </div>
                </el-form-item>

                <el-form-item label="特殊要求">
                  <el-input
                      v-model="worldGenerateConfig.customPrompt"
                      type="textarea"
                      :rows="3"
                      placeholder="例如：需要包含特定的种族设定、独特的政治制度、特殊的自然现象等..."
                  />
                </el-form-item>
              </el-form>
            </el-card>

            <!-- 流式生成区域 -->
            <el-card v-if="worldGenerating" shadow="never" class="streaming-section">
              <template #header>
                <span>🤖 AI正在生成世界观设定...</span>
              </template>

              <div class="streaming-content-container">
                <div class="streaming-content" v-html="formatStreamingContent(streamingContent)"></div>
              </div>
            </el-card>

            <!-- 生成结果区域 -->
            <el-card v-if="!worldGenerating && generatedWorldSettings.length > 0" shadow="never" class="results-section">
              <template #header>
                <div class="results-header">
                  <span>✨ 生成结果 ({{ generatedWorldSettings.length }}个设定)</span>
                  <div class="result-actions">
                    <el-button size="small" @click="() => generatedWorldSettings.forEach(setting => setting.selected = true)">全选</el-button>
                    <el-button size="small" @click="() => generatedWorldSettings.forEach(setting => setting.selected = false)">全不选</el-button>
                  </div>
                </div>
              </template>

              <div class="generated-settings-list">
                <div
                    v-for="setting in generatedWorldSettings"
                    :key="setting.id"
                    class="generated-setting-card"
                    :class="{ selected: setting.selected !== false }"
                    @click="toggleWorldSettingSelection(setting)"
                >
                  <div class="setting-header">
                    <div class="setting-basic-info">
                      <h4>{{ setting.title }}</h4>
                      <el-tag :type="getWorldSettingType(setting.type)" size="small">{{ setting.type }}</el-tag>
                    </div>
                    <div class="selection-indicator">
                      <el-icon v-if="setting.selected !== false" class="selected-icon"><Check /></el-icon>
                    </div>
                  </div>

                  <div class="setting-content">
                    <p>{{ setting.description || '暂无描述' }}</p>
                  </div>
                </div>
              </div>
            </el-card>
          </div>

          <template #footer>
            <div class="dialog-footer">
              <el-button @click="showWorldGenerateDialog = false">取消</el-button>
              <el-button
                  v-if="!worldGenerating && generatedWorldSettings.length === 0"
                  type="primary"
                  @click="generateWorldSettings"
                  :disabled="!worldGenerateConfig.includeGeography && !worldGenerateConfig.includeCulture && !worldGenerateConfig.includeHistory && !worldGenerateConfig.includeMagic && !worldGenerateConfig.includeTechnology && !worldGenerateConfig.includePolitics && !worldGenerateConfig.includeReligion && !worldGenerateConfig.includeEconomy && !worldGenerateConfig.includeRaces && !worldGenerateConfig.includeLanguage"
              >
                🚀 开始生成
              </el-button>
              <el-button
                  v-if="!worldGenerating && generatedWorldSettings.length > 0"
                  @click="generateWorldSettings"
              >
                🔄 重新生成
              </el-button>
              <el-button
                  v-if="!worldGenerating && generatedWorldSettings.length > 0"
                  type="primary"
                  @click="confirmAddGeneratedWorldSettings"
              >
                ✅ 添加选中设定
              </el-button>
            </div>
          </template>
        </el-dialog>

        <!-- 提示词选择对话框 -->
        <el-dialog v-model="showPromptDialog" title="选择提示词" width="800px" @close="resetPromptDialog">
          <div class="prompt-dialog-content">
            <!-- 提示词列表 -->
            <div class="prompt-list">
              <h4>{{ getCategoryName() }} 提示词</h4>
              <div class="prompt-cards">
                <div
                    v-for="prompt in getPromptsByCategory(selectedPromptCategory)"
                    :key="prompt.id"
                    class="prompt-card"
                    :class="{ active: selectedPrompt?.id === prompt.id }"
                    @click="selectPrompt(prompt)"
                >
                  <div class="prompt-card-header">
                    <h5>{{ prompt.title }}</h5>
                  </div>
                  <div class="prompt-card-description">
                    <p>{{ prompt.description }}</p>
                  </div>
                  <div class="prompt-card-tags">
                    <el-tag v-for="tag in prompt.tags" :key="tag" size="small">{{ tag }}</el-tag>
                  </div>
                </div>
              </div>

              <div v-if="getPromptsByCategory(selectedPromptCategory).length === 0" class="empty-prompts">
                <p>暂无该类型的提示词</p>
                <el-button type="primary" @click="goToPromptLibrary">去提示词库添加</el-button>
              </div>
            </div>

            <!-- 变量填充区域 -->
            <div v-if="selectedPrompt && Object.keys(promptVariables).length > 0" class="prompt-variables">
              <h4>填充变量</h4>
              <el-form label-width="120px" size="small">
                <el-form-item
                    v-for="(value, variable) in promptVariables"
                    :key="variable"
                    :label="variable + '：'"
                >
                  <el-input
                      v-model="promptVariables[variable]"
                      :placeholder="'请输入' + variable"
                      @input="generateFinalPrompt"
                  />
                </el-form-item>
              </el-form>
            </div>

            <!-- 最终提示词预览 -->
            <div v-if="selectedPrompt" class="final-prompt">
              <h4>最终提示词预览</h4>
              <el-input
                  v-model="finalPrompt"
                  type="textarea"
                  :rows="8"
                  readonly
                  placeholder="请先选择提示词并填充变量"
              />
            </div>
          </div>

          <!-- 批量章节生成时的流式内容显示 -->
          <div v-if="isStreaming && streamingType === 'batch-chapters' && showAIBatchChapterDialog" class="streaming-content-area">
            <el-card shadow="never" class="streaming-card">
              <template #header>
                <div class="streaming-header">
                  <span>🔄 AI正在批量生成章节大纲...</span>
                  <el-tag type="success" size="small">实时生成中...</el-tag>
                  <el-button size="small" @click="stopStreaming">停止生成</el-button>
                </div>
              </template>
              <div class="streaming-content">
                <pre class="streaming-text-plain">{{ streamingContent }}</pre>
              </div>
            </el-card>
          </div>

          <template #footer>
            <el-button @click="showPromptDialog = false">取消</el-button>
            <el-button v-if="selectedPrompt" @click="copyPromptToClipboard">复制提示词</el-button>
            <el-button v-if="selectedPrompt" type="primary" @click="useSelectedPrompt" :loading="isStreaming && streamingType === 'batch-chapters'">
              {{ isStreaming && streamingType === 'batch-chapters' ? '生成中...' : '使用此提示词' }}
            </el-button>
          </template>
        </el-dialog>

        <!-- AI生成单章对话框 -->
        <el-dialog v-model="showAISingleChapterDialog" title="AI生成单章" width="800px" @close="resetAISingleChapterDialog">
          <div class="ai-single-chapter-content">
            <el-form :model="aiSingleChapterForm" label-width="120px">
              <el-form-item label="章节标题">
                <el-input v-model="aiSingleChapterForm.title" placeholder="请输入章节标题" />
              </el-form-item>
              <el-form-item label="情节要求">
                <el-input v-model="aiSingleChapterForm.plotRequirement" type="textarea" :rows="3" placeholder="描述希望的情节发展..." />
              </el-form-item>
              <el-form-item label="提示词模板">
                <el-select v-model="aiSingleChapterForm.template" placeholder="选择模板">
                  <el-option label="通用章节" value="general" />
                  <el-option label="战斗场景" value="battle" />
                  <el-option label="情感戏" value="emotion" />
                  <el-option label="转折剧情" value="turning" />
                </el-select>
              </el-form-item>
            </el-form>

            <!-- 自定义提示词状态显示 -->
            <div v-if="singleChapterSelectedPrompt" class="custom-prompt-status">
              <el-alert
                  :title="`已选择自定义提示词：${singleChapterSelectedPrompt.title}`"
                  type="success"
                  show-icon
                  :closable="false"
              >
                <div class="prompt-preview">
                  {{ singleChapterSelectedPrompt.description || '自定义提示词已准备就绪，点击"生成章节"按钮开始使用此提示词生成章节' }}
                </div>
              </el-alert>
            </div>

            <!-- 流式生成内容显示 -->
            <div v-if="isStreaming && streamingType === 'single-chapter'" class="streaming-content-area">
              <el-card shadow="never" class="streaming-card">
                <template #header>
                  <div class="streaming-header">
                    <span>🔄 AI正在生成章节大纲...</span>
                    <el-tag type="success" size="small">实时生成中...</el-tag>
                  </div>
                </template>
                <div class="streaming-content">
                  <pre class="streaming-text-plain">{{ streamingContent }}</pre>
                </div>
              </el-card>
            </div>
          </div>
          <template #footer>
            <el-button @click="showAISingleChapterDialog = false">取消</el-button>
            <el-button @click="selectPromptForSingleChapter">选择提示词</el-button>
            <el-button type="primary" @click="generateSingleChapter" :loading="isGeneratingChapters">
              <el-icon><Star /></el-icon>
              {{ singleChapterSelectedPrompt ? '使用自定义提示词生成' : '生成章节' }}
            </el-button>
          </template>
        </el-dialog>
        <!-- AI批量生成章节对话框 -->
        <el-dialog v-model="showAIBatchChapterDialog" title="AI批量生成章节" width="900px" @close="resetAIBatchChapterDialog">
          <div class="ai-batch-chapter-content">
            <el-form :model="aiBatchChapterForm" label-width="120px">
              <el-form-item label="生成数量">
                <el-input-number v-model="aiBatchChapterForm.count" :min="1" :max="10" />
              </el-form-item>
              <el-form-item label="情节要求">
                <el-input v-model="aiBatchChapterForm.plotRequirement" type="textarea" :rows="3" placeholder="描述希望的情节发展..." />
              </el-form-item>
              <el-form-item label="提示词模板">
                <el-select v-model="aiBatchChapterForm.template" placeholder="选择模板">
                  <el-option label="通用章节" value="general" />
                  <el-option label="战斗场景" value="battle" />
                  <el-option label="情感戏" value="emotion" />
                  <el-option label="转折剧情" value="turning" />
                </el-select>
              </el-form-item>
            </el-form>

            <!-- 自定义提示词状态显示 -->
            <div v-if="batchChapterSelectedPrompt" class="custom-prompt-status">
              <el-alert
                  :title="`已选择自定义提示词：${batchChapterSelectedPrompt.title}`"
                  type="success"
                  show-icon
                  :closable="false"
              >
                <div class="prompt-preview">
                  {{ batchChapterSelectedPrompt.description || '自定义提示词已准备就绪，点击"批量生成"按钮开始使用此提示词生成章节' }}
                </div>
              </el-alert>

              <!-- 提示词内容预览 -->
              <el-collapse v-model="activePromptCollapse" class="prompt-content-collapse">
                <el-collapse-item title="查看提示词内容" name="promptContent">
                  <div class="prompt-content-preview">
                    <div class="prompt-content-header">
                      <span class="content-label">原始提示词内容：</span>
                    </div>
                    <div class="prompt-content-text">
                      {{ batchChapterSelectedPrompt.content }}
                    </div>

                    <div v-if="batchChapterFinalPrompt" class="final-prompt-section">
                      <div class="prompt-content-header">
                        <span class="content-label">填充变量后的最终提示词：</span>
                      </div>
                      <div class="prompt-content-text final-prompt">
                        {{ batchChapterFinalPrompt }}
                      </div>
                    </div>
                  </div>
                </el-collapse-item>
              </el-collapse>
            </div>

            <!-- 流式生成内容显示 -->
            <div v-if="isStreaming && streamingType === 'batch-chapters'" class="streaming-content-area">
              <el-card shadow="never" class="streaming-card">
                <template #header>
                  <div class="streaming-header">
                    <span>🔄 AI正在批量生成章节大纲...</span>
                    <el-tag type="success" size="small">实时生成中...</el-tag>
                  </div>
                </template>
                <div class="streaming-content">
                  <pre class="streaming-text-plain">{{ streamingContent }}</pre>
                </div>
              </el-card>
            </div>
          </div>
          <template #footer>
            <el-button @click="showAIBatchChapterDialog = false">取消</el-button>
            <el-button @click="selectPromptForBatchChapter">选择提示词</el-button>
            <el-button type="primary" @click="generateBatchChapters" :loading="isGeneratingChapters">
              <el-icon><Star /></el-icon>
              {{ batchChapterSelectedPrompt ? '使用自定义提示词生成' : '批量生成' }}
            </el-button>
          </template>
        </el-dialog>

        <!-- 新的AI优化对话框 -->
        <el-dialog
            v-model="showNewOptimizeDialog"
            title="AI文本润色"
            width="1200px"
            @close="resetOptimizeDialog"
        >
          <div class="new-optimize-container">
            <el-row :gutter="20">
              <!-- 左侧：配置区域 -->
              <el-col :span="8">
                <el-card shadow="never" class="optimize-config-card">
                  <template #header>
                    <div class="card-header">
                      <span>⚙️ 润色配置</span>
                      <el-tag v-if="optimizeForm.mode === 'selection'" type="info" size="small">选择内容</el-tag>
                      <el-tag v-else type="warning" size="small">整篇文章</el-tag>
                    </div>
                  </template>

                  <!-- 预设提示词选择 -->
                  <div class="prompt-selection">
                    <h4>选择润色类型</h4>
                    <div class="prompt-list">
                      <div
                          v-for="prompt in optimizePrompts"
                          :key="prompt.id"
                          class="prompt-item"
                          :class="{ active: optimizeForm.selectedPrompt?.id === prompt.id }"
                          @click="selectNewOptimizePrompt(prompt)"
                      >
                        <div class="prompt-title">{{ prompt.title }}</div>
                        <div class="prompt-desc">{{ prompt.description || prompt.content.substring(0, 60) + '...' }}</div>
                      </div>
                    </div>
                    <div v-if="optimizePrompts.length === 0" class="empty-prompts">
                      <p>暂无润色提示词</p>
                      <el-button size="small" @click="goToPromptLibrary">去提示词库添加</el-button>
                    </div>
                  </div>

                  <!-- 自定义提示词 -->
                  <div class="custom-prompt">
                    <h4>自定义润色要求</h4>
                    <el-input
                        v-model="optimizeForm.customPrompt"
                        type="textarea"
                        :rows="4"
                        placeholder="输入具体的润色要求，例如：提升文字的画面感、增强对话的真实感、优化句式结构等..."
                    />
                  </div>

                  <!-- 原始内容预览 -->
                  <div class="original-content-preview">
                    <h4>原始内容预览</h4>
                    <el-input
                        :value="optimizeForm.originalContent"
                        type="textarea"
                        :rows="8"
                        readonly
                        placeholder="暂无内容"
                        class="original-content-textarea"
                    />
                    <div class="content-stats">
                      字数：{{ optimizeForm.originalContent.length }}
                    </div>
                  </div>
                </el-card>
              </el-col>

              <!-- 右侧：优化结果区域 -->
              <el-col :span="16">
                <el-card shadow="never" class="optimize-result-card">
                  <template #header>
                    <div class="card-header">
                      <span>✨ 润色结果</span>
                      <el-button
                          v-if="optimizeForm.optimizedContent && !isOptimizeStreaming"
                          type="success"
                          size="small"
                          @click="copyOptimizedContent"
                      >
                        <el-icon><CopyDocument /></el-icon>
                        复制结果
                      </el-button>
                    </div>
                  </template>

                  <!-- 流式输出区域 -->
                  <div v-if="isOptimizeStreaming" class="streaming-area">
                    <div class="streaming-header">
                      <span class="streaming-status">🤖 AI正在润色中...</span>
                      <el-button size="small" type="text" @click="stopOptimizeStreaming">
                        <el-icon><Close /></el-icon>
                        停止
                      </el-button>
                    </div>
                    <div class="streaming-content-box">
                      <div class="streaming-text">{{ optimizeStreamingContent }}</div>
                    </div>
                  </div>

                  <!-- 优化结果显示 -->
                  <div v-else-if="optimizeForm.optimizedContent" class="result-area">
                    <div class="result-content">
                      {{ optimizeForm.optimizedContent }}
                    </div>
                    <div class="result-stats">
                      <span>润色后字数：{{ optimizeForm.optimizedContent.length }}</span>
                      <span>字数变化：{{ optimizeForm.optimizedContent.length - optimizeForm.originalContent.length > 0 ? '+' : '' }}{{ optimizeForm.optimizedContent.length - optimizeForm.originalContent.length }}</span>
                    </div>
                  </div>

                  <!-- 空状态 -->
                  <div v-else class="empty-result">
                    <el-empty description="点击润色按钮开始AI润色" />
                  </div>
                </el-card>
              </el-col>
            </el-row>
          </div>

          <template #footer>
            <div class="dialog-footer">
              <el-button @click="showNewOptimizeDialog = false">取消</el-button>
              <el-button
                  type="primary"
                  @click="startNewOptimize"
                  :loading="isOptimizeStreaming"
                  :disabled="!canStartOptimize"
              >
                <el-icon><MagicStick /></el-icon>
                {{ isOptimizeStreaming ? '润色中...' : '开始润色' }}
              </el-button>
              <el-button
                  v-if="optimizeForm.optimizedContent && optimizeForm.mode === 'selection'"
                  type="success"
                  @click="replaceSelectedContent"
              >
                <el-icon><Check /></el-icon>
                替换选择内容
              </el-button>
              <el-button
                  v-if="optimizeForm.optimizedContent && optimizeForm.mode === 'full'"
                  type="success"
                  @click="replaceFullContent"
              >
                <el-icon><Check /></el-icon>
                替换全文内容
              </el-button>
            </div>
          </template>
        </el-dialog>

        <!-- 新的AI续写对话框 -->
        <el-dialog
            v-model="showNewContinueDialog"
            title="AI智能续写"
            width="1000px"
            top="5vh"
            @close="resetContinueDialog"
        >
          <div class="new-continue-container">
            <el-row :gutter="20" style="height: 100%;">
              <!-- 左侧：配置区域 -->
              <el-col :span="10" style="height: 100%;">
                <el-card shadow="never" class="continue-config-card">
                  <template #header>
                    <div class="card-header">
                      <span>⚙️ 续写配置</span>
                    </div>
                  </template>

                  <!-- 续写方向 -->
                  <div class="continue-direction">
                    <h4>续写方向</h4>
                    <el-input
                        v-model="continueForm.direction"
                        type="textarea"
                        :rows="6"
                        placeholder="请描述续写方向，例如：&#10;- 推进主角与反派的对决&#10;- 展现角色内心的纠结&#10;- 描写紧张的追逐场面&#10;- 揭示重要的秘密&#10;&#10;留空将根据大纲和前文自动续写"
                    />
                  </div>

                  <!-- 续写字数 -->
                  <div class="continue-word-count">
                    <h4>续写字数</h4>
                    <el-slider
                        v-model="continueForm.wordCount"
                        :min="200"
                        :max="5000"
                        :step="100"
                        show-stops
                        show-input
                    />
                    <div class="word-count-tips">
                      <span>建议：200-1000字为佳，最多支持5000字</span>
                    </div>
                  </div>

                  <!-- 当前内容预览 -->
                  <div class="current-content-preview">
                    <h4>当前内容</h4>
                    <el-input
                        :model-value="getCurrentFullContent()"
                        type="textarea"
                        :rows="6"
                        readonly
                        placeholder="暂无内容"
                        style="max-height: 150px;"
                    />
                    <div class="content-stats">
                      当前字数：{{ contentWordCount }}
                    </div>
                  </div>
                </el-card>
              </el-col>

              <!-- 右侧：续写结果区域 -->
              <el-col :span="14" style="height: 100%;">
                <el-card shadow="never" class="continue-result-card">
                  <template #header>
                    <div class="card-header">
                      <span>✍️ 续写结果</span>
                      <el-button
                          v-if="continueStreamingContent && !isContinueStreaming"
                          type="success"
                          size="small"
                          @click="copyContinueContent"
                      >
                        <el-icon><CopyDocument /></el-icon>
                        复制结果
                      </el-button>
                    </div>
                  </template>

                  <!-- 流式输出区域 -->
                  <div v-if="isContinueStreaming" class="streaming-area">
                    <div class="streaming-header">
                      <span class="streaming-status">🤖 AI正在续写中...</span>
                      <el-button size="small" type="text" @click="stopContinueStreaming">
                        <el-icon><Close /></el-icon>
                        停止
                      </el-button>
                    </div>
                    <div class="streaming-content-box">
                      <div class="streaming-text">{{ continueStreamingContent }}</div>
                    </div>
                  </div>

                  <!-- 续写结果显示 -->
                  <div v-else-if="continueStreamingContent" class="result-area">
                    <div class="result-content">
                      {{ continueStreamingContent }}
                    </div>
                    <div class="result-stats">
                      <span>续写字数：{{ continueStreamingContent.length }}</span>
                      <span>总字数：{{ contentWordCount + continueStreamingContent.length }}</span>
                    </div>
                  </div>

                  <!-- 空状态 -->
                  <div v-else class="empty-result">
                    <el-empty description="点击续写按钮开始AI续写" />
                  </div>
                </el-card>
              </el-col>
            </el-row>
          </div>

          <template #footer>
            <div class="dialog-footer">
              <el-button @click="showNewContinueDialog = false">取消</el-button>
              <el-button
                  type="primary"
                  @click="startNewContinue"
                  :loading="isContinueStreaming"
                  :disabled="!canStartContinue"
              >
                <el-icon><ArrowRight /></el-icon>
                {{ isContinueStreaming ? '续写中...' : '开始续写' }}
              </el-button>
              <el-button
                  v-if="continueStreamingContent && !isContinueStreaming"
                  type="success"
                  @click="appendContinueContent"
              >
                <el-icon><Check /></el-icon>
                追加到文章
              </el-button>
            </div>
          </template>
        </el-dialog>

        <!-- 大纲生成对话框 -->
        <el-dialog 
          v-model="showOutlineGenerateDialog" 
          title="AI生成章节大纲" 
          width="800px" 
          @close="resetOutlineDialog"
        >
          <div class="outline-generate-content">
            <div class="chapter-info-section">
              <el-card shadow="never" style="margin-bottom: 16px;">
                <div class="chapter-info-header">
                  <h4>📖 章节信息</h4>
                  <el-tag v-if="generatingOutlineChapter" type="info" size="small">
                    {{ generatingOutlineChapter.title }}
                  </el-tag>
                </div>
                <div v-if="generatingOutlineChapter" class="chapter-stats">
                  <span class="stat-item">字数：{{ generatingOutlineChapter.wordCount || '未统计' }}字</span>
                  <span class="stat-item">状态：{{ getChapterStatusText(generatingOutlineChapter.status) }}</span>
                </div>
              </el-card>
            </div>

            <div class="outline-result-section">
              <div class="section-header">
                <h4>🎯 生成的大纲</h4>
                <el-button 
                  v-if="!isGeneratingOutlineDialog && generatedOutlineContent"
                  size="small"
                  @click="generateOutlineWithDialog"
                >
                  🔄 重新生成
                </el-button>
              </div>
              
              <el-card shadow="never" class="outline-content-card">
                <div v-if="isGeneratingOutlineDialog" class="generating-status">
                  <div class="generating-indicator">
                    <el-icon class="is-loading"><Loading /></el-icon>
                    <span>AI正在分析章节内容，生成大纲...</span>
                  </div>
                </div>
                
                <div v-show="generatedOutlineContent" class="outline-content">
                  <div class="outline-text">{{ generatedOutlineContent }}</div>
                </div>
                
                <div v-if="!isGeneratingOutlineDialog && !generatedOutlineContent" class="outline-placeholder">
                  <p>点击"开始生成"按钮，AI将分析章节内容并生成结构化大纲</p>
                </div>
              </el-card>
            </div>
          </div>

          <template #footer>
            <div class="dialog-footer">
              <el-button @click="showOutlineGenerateDialog = false">取消</el-button>
              <el-button 
                v-if="!generatedOutlineContent && !isGeneratingOutlineDialog"
                type="primary"
                @click="generateOutlineWithDialog"
              >
                🚀 开始生成
              </el-button>
              <el-button 
                v-if="generatedOutlineContent && !isGeneratingOutlineDialog"
                type="success"
                @click="confirmSaveOutline"
              >
                ✅ 确认保存
              </el-button>
            </div>
          </template>
        </el-dialog>

        <!-- 批量大纲生成对话框 -->
        <el-dialog 
          v-model="showBatchOutlineDialog" 
          title="AI批量生成章节大纲" 
          width="900px" 
          @close="resetBatchOutlineDialog"
        >
          <div class="batch-outline-content">
            <!-- 配置区域 -->
            <div class="config-section">
              <el-card shadow="never" style="margin-bottom: 16px;">
                <template #header>
                  <h4>⚙️ 生成配置</h4>
                </template>
                <div class="config-options">
                  <el-checkbox 
                    v-model="batchOutlineConfig.includeChaptersWithContent" 
                    @change="updateSelectedBatchChapters"
                  >
                    包含有内容的章节
                  </el-checkbox>
                  <el-checkbox 
                    v-model="batchOutlineConfig.includeChaptersWithoutOutline" 
                    @change="updateSelectedBatchChapters"
                    :disabled="!batchOutlineConfig.includeChaptersWithContent"
                  >
                    包含没有大纲的章节
                  </el-checkbox>
                  <el-checkbox 
                    v-model="batchOutlineConfig.overwriteExistingOutline" 
                    @change="updateSelectedBatchChapters"
                    :disabled="!batchOutlineConfig.includeChaptersWithContent"
                  >
                    覆盖已有大纲
                  </el-checkbox>
                </div>
              </el-card>
            </div>

            <!-- 章节选择区域 -->
            <div class="chapters-selection-section">
              <el-card shadow="never" style="margin-bottom: 16px;">
                <template #header>
                  <div class="section-header">
                    <h4>📚 待生成章节 ({{ selectedBatchChapters.length }})</h4>
                    <el-button size="small" @click="updateSelectedBatchChapters">
                      🔄 刷新列表
                    </el-button>
                  </div>
                </template>
                <div v-if="selectedBatchChapters.length > 0" class="chapters-list">
                  <div 
                    v-for="(chapter, index) in selectedBatchChapters" 
                    :key="chapter.id"
                    class="chapter-preview-item"
                  >
                    <div class="chapter-info">
                      <h5>{{ chapter.title }}</h5>
                      <div class="chapter-meta">
                        <span>{{ chapter.wordCount || 0 }}字</span>
                        <el-tag 
                          :type="chapter.description ? 'warning' : 'info'" 
                          size="small"
                        >
                          {{ chapter.description ? '有大纲' : '无大纲' }}
                        </el-tag>
                      </div>
                    </div>
                  </div>
                </div>
                <div v-else class="no-chapters">
                  <p>没有符合条件的章节</p>
                  <p class="hint">请调整配置条件或确保章节有内容</p>
                </div>
              </el-card>
            </div>

            <!-- 进度显示 -->
            <div v-if="batchOutlineGenerating" class="progress-section">
              <el-card shadow="never" style="margin-bottom: 16px;">
                <template #header>
                  <h4>🚀 生成进度</h4>
                </template>
                <div class="progress-content">
                  <el-progress 
                    :percentage="Math.round((batchOutlineProgress.current / batchOutlineProgress.total) * 100)"
                    :status="batchOutlineProgress.current === batchOutlineProgress.total ? 'success' : null"
                  />
                  <div class="progress-text">
                    正在生成: {{ batchOutlineProgress.currentChapter }}
                    ({{ batchOutlineProgress.current }}/{{ batchOutlineProgress.total }})
                  </div>
                </div>
              </el-card>
            </div>

                         <!-- 结果显示 -->
             <div v-if="batchOutlineResults.length > 0" class="results-section">
               <el-card shadow="never">
                 <template #header>
                   <div class="section-header">
                     <h4>📊 生成结果</h4>
                     <div class="result-actions">
                       <div class="result-stats">
                         <el-tag type="success" size="small">
                           成功: {{ batchOutlineResults.filter(r => r.status === 'success').length }}
                         </el-tag>
                         <el-tag type="danger" size="small">
                           失败: {{ batchOutlineResults.filter(r => r.status === 'error').length }}
                         </el-tag>
                         <el-tag type="info" size="small">
                           已选: {{ batchOutlineResults.filter(r => r.selected).length }}
                         </el-tag>
                       </div>
                       <div class="select-actions">
                         <el-button 
                           size="small" 
                           @click="toggleSelectAllOutlines(true)"
                           :disabled="batchOutlineResults.filter(r => r.status === 'success').length === 0"
                         >
                           全选
                         </el-button>
                         <el-button 
                           size="small" 
                           @click="toggleSelectAllOutlines(false)"
                         >
                           取消全选
                         </el-button>
                       </div>
                     </div>
                   </div>
                 </template>
                 <div class="results-list">
                   <div 
                     v-for="result in batchOutlineResults" 
                     :key="result.chapterId"
                     class="result-item"
                     :class="{ 
                       success: result.status === 'success', 
                       error: result.status === 'error',
                       selected: result.selected 
                     }"
                   >
                     <div class="result-header">
                       <div class="chapter-info">
                         <el-checkbox 
                           v-if="result.status === 'success'"
                           v-model="result.selected"
                           class="chapter-checkbox"
                         />
                         <span class="chapter-name">{{ result.chapter }}</span>
                       </div>
                       <el-tag 
                         :type="result.status === 'success' ? 'success' : 'danger'" 
                         size="small"
                       >
                         {{ result.status === 'success' ? '成功' : '失败' }}
                       </el-tag>
                     </div>
                     <div v-if="result.status === 'error'" class="error-message">
                       错误: {{ result.error }}
                     </div>
                     <div v-else-if="result.content" class="result-content">
                       <div class="content-preview">
                         <div class="content-text">{{ result.content }}</div>
                         <div v-if="result.originalOutline" class="original-outline">
                           <div class="original-outline-label">原大纲：</div>
                           <div class="original-outline-text">{{ result.originalOutline }}</div>
                         </div>
                       </div>
                     </div>
                   </div>
                 </div>
               </el-card>
             </div>
          </div>

          <template #footer>
            <div class="dialog-footer">
              <el-button @click="showBatchOutlineDialog = false">取消</el-button>
              <el-button 
                v-if="!batchOutlineGenerating && batchOutlineResults.length === 0"
                type="primary"
                @click="startBatchOutlineGenerate"
                :disabled="selectedBatchChapters.length === 0"
              >
                🚀 开始批量生成 ({{ selectedBatchChapters.length }}个章节)
              </el-button>
              <el-button 
                v-if="!batchOutlineGenerating && batchOutlineResults.length > 0"
                @click="startBatchOutlineGenerate"
              >
                🔄 重新生成
              </el-button>
                             <el-button 
                 v-if="batchOutlineResults.length > 0 && batchOutlineResults.filter(r => r.status === 'success').length > 0"
                 type="success"
                 @click="saveBatchOutlines"
                 :disabled="batchSaving || batchOutlineResults.filter(r => r.selected).length === 0"
                 :loading="batchSaving"
               >
                 ✅ 确认保存 ({{ batchOutlineResults.filter(r => r.selected).length }})
               </el-button>
            </div>
          </template>
        </el-dialog>
      </div>
      <!-- 右侧纵向标签栏 -->
      <div class="right-tabs-panel">
        <div class="vertical-tabs">
          <div
              v-for="tab in tabList"
              :key="tab.name"
              class="vertical-tab-item"
              :class="{ active: activeTab === tab.name }"
              @click="activeTab = tab.name"
          >
            <div class="tab-icon">{{ tab.icon }}</div>
            <div class="tab-label">{{ tab.label }}</div>
          </div>
        </div>
      </div>
    </div>

  </div>
</template>

<script setup>
import { ref, computed, onMounted, onUnmounted, watch, shallowRef, nextTick } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus'
import {
  ArrowLeft, DocumentAdd, Plus, Edit, Delete, Document, MoreFilled, ArrowDown, Star, Tools, ArrowRight, Right, Check, InfoFilled, MagicStick, Close, CopyDocument, Loading
} from '@element-plus/icons-vue'
import QuillEditor from '../components/QuillEditor.vue'
import apiService from '../services/api.js'
import billingService from '../services/billing.js'
import { useNovelStore } from '../stores/novel.js'
import { novelApi, chapterApi, characterApi, worldSettingApi, corpusApi, eventApi, promptApi } from '../services/novelApi.js'
import ChapterListPanel from '../components/ChapterListPanel.vue'
import CharacterListPanel from '../components/CharacterListPanel.vue'
import WorldviewListPanel from '../components/WorldviewListPanel.vue'
import CorpusListPanel from '../components/CorpusListPanel.vue'
import EventTimelinePanel from '../components/EventTimelinePanel.vue'
import ChapterGenerateDialog from '../components/ChapterGenerateDialog.vue'

const route = useRoute()
const router = useRouter()
const novelStore = useNovelStore()

// API服务实例已经在api.js中创建并导出

// 检查API配置
const checkApiConfig = () => {
  const config = apiService.getConfig()
  if (!config.apiKey || !config.baseURL) {
    ElMessageBox.confirm(
        '检测到您还未配置AI API，需要先配置API密钥才能使用AI功能。是否前往配置？',
        '需要配置API',
        {
          confirmButtonText: '去配置',
          cancelButtonText: '稍后配置',
          type: 'warning'
        }
    ).then(() => {
      router.push('/config')
    }).catch(() => {
      // 用户选择稍后配置
    })
    return false
  }
  return true
}

// 检查API配置（移除余额检查，用户使用自己的API）
const checkApiAndBalance = () => {
  return checkApiConfig()
}

// 响应式数据
const currentNovel = ref(null)
const chapters = ref([])
const currentChapter = ref(null)
const content = ref('')
const hasUnsavedChanges = ref(false)
const isSaving = ref(false)
const isComponentMounted = ref(true) // 添加组件挂载状态标志

// 分页相关数据
const chapterPagination = ref({
  current: 1,
  size: 10,
  total: 0
})

// 页面加载状态
const pageLoading = ref(false)
const chaptersLoading = ref(false)
const charactersLoading = ref(false)
const worldSettingsLoading = ref(false)
const corpusLoading = ref(false)
const eventsLoading = ref(false)
const showChapterDialog = ref(false)
const editingChapter = ref(null)
const editorRef = shallowRef()
const activeTab = ref('editor')

// 标签列表数据
const tabList = ref([
  { name: 'editor', label: '目录', icon: '📝' },
  { name: 'characters', label: '人物', icon: '👥' },
  { name: 'worldview', label: '世界观', icon: '🌍' },
  { name: 'corpus', label: '语料库', icon: '📚' },
  { name: 'events', label: '事件线', icon: '📊' }
])

// AI相关数据
const isGeneratingChapters = ref(false)
const isGeneratingContent = ref(false)
const isOptimizing = ref(false)
const isGeneratingOutline = ref(false)
const optimizeType = ref('grammar')

// 大纲生成对话框相关
const showOutlineGenerateDialog = ref(false)
const generatingOutlineChapter = ref(null)
const generatedOutlineContent = ref('')
const isGeneratingOutlineDialog = ref(false)

// 批量大纲生成对话框相关
const showBatchOutlineDialog = ref(false)
const batchOutlineGenerating = ref(false)
const batchOutlineConfig = ref({
  includeChaptersWithContent: true,  // 包含有内容的章节
  includeChaptersWithoutOutline: true,  // 包含没有大纲的章节
  overwriteExistingOutline: false  // 覆盖已有大纲
})
const batchOutlineProgress = ref({
  current: 0,
  total: 0,
  currentChapter: ''
})
const batchOutlineResults = ref([])
const selectedBatchChapters = ref([])
const batchSaving = ref(false)
// 流式生成相关数据
const streamingContent = ref('')
const isStreaming = ref(false)
const streamingType = ref('') // 'content', 'chapter', 'optimize', 'continue'
const streamingChapter = ref(null)

// 提示词相关数据
const showPromptDialog = ref(false)
const selectedPromptCategory = ref('')
const availablePrompts = ref([])
const selectedPrompt = ref(null)
const promptVariables = ref({})
const finalPrompt = ref('')

// AI优化提示词选择
const showOptimizePromptDialog = ref(false)
const optimizeSelectedPrompt = ref(null)
const optimizePromptVariables = ref({})
const optimizeFinalPrompt = ref('')
const activeMaterialTab = ref('characters')

// 章节生成对话框相关数据
const showChapterGenerateDialog = ref(false)
const isDevelopment = ref(true) // 开发模式，可以显示调试功能
const targetChapter = ref(null)
const selectedContentCategory = ref('content') // 当前选择的正文分类
const selectedMaterials = ref({
  characters: [],
  worldSettings: [],
  corpus: [],
  events: [],
  chapters: []
})

// 前文概要章节选择
const selectedContextChapters = ref([])

// 正文生成分类
const contentCategories = ref([
  { key: 'content', name: '基础正文', icon: '📝' },
  { key: 'content-dialogue', name: '对话生成', icon: '💬' },
  { key: 'content-scene', name: '场景描写', icon: '🏞️' },
  { key: 'content-action', name: '动作情节', icon: '⚡' },
  { key: 'content-psychology', name: '心理描写', icon: '🧠' }
])

// 批量生成角色相关数据
const showBatchGenerateCharacterDialog = ref(false)
const batchGenerateConfig = ref({
  count: 5,
  includeMainCharacters: true,
  includeSupportingCharacters: true,
  includeMinorCharacters: true,
  customPrompt: '',
  autoAssignRoles: true
})
const batchGenerating = ref(false)
const generatedCharacters = ref([])
const batchGenerateResults = ref([])

// 批量生成提示词相关数据
const batchCharacterSelectedPrompt = ref(null)
const batchCharacterPromptVariables = ref({})
const batchCharacterFinalPrompt = ref('')

// 世界观AI生成相关数据
const showWorldGenerateDialog = ref(false)
const worldGenerateConfig = ref({
  count: 3,
  includeGeography: true,
  includeCulture: true,
  includeHistory: true,
  includeMagic: false,
  includeTechnology: false,
  includePolitics: false,
  includeReligion: false,
  includeEconomy: false,
  includeRaces: false,
  includeLanguage: false,
  customPrompt: ''
})
const worldGenerating = ref(false)
const generatedWorldSettings = ref([])
const isGeneratingWorldSetting = ref(false)
// 世界观生成提示词相关数据
const worldSettingSelectedPrompt = ref(null)
const worldSettingPromptVariables = ref({})
const worldSettingFinalPrompt = ref('')

// 新增AI功能弹窗相关数据
const showAISingleChapterDialog = ref(false)
const showAIBatchChapterDialog = ref(false)
const showAIOptimizeDialog = ref(false)

// AI单章生成表单
const aiSingleChapterForm = ref({
  title: '',
  plotRequirement: '',
  template: 'general'
})

// AI批量生成章节表单
const aiBatchChapterForm = ref({
  count: 3,
  plotRequirement: '',
  template: 'general'
})

// 批量生成章节选中的提示词
const batchChapterSelectedPrompt = ref(null)
const batchChapterPromptVariables = ref({})
const batchChapterFinalPrompt = ref('')
const activePromptCollapse = ref(['promptContent']) // 默认展开提示词内容

// 单章生成选中的提示词
const singleChapterSelectedPrompt = ref(null)
const singleChapterPromptVariables = ref({})
const singleChapterFinalPrompt = ref('')

// 新的优化对话框相关数据
const showNewOptimizeDialog = ref(false)
const optimizeForm = ref({
  originalContent: '',
  optimizedContent: '',
  customPrompt: '',
  selectedPrompt: null,
  mode: 'full', // 'selection' | 'full'
  isOptimizing: false
})
// 润色优化提示词 - 从提示词库的润色分类中获取
const optimizePrompts = computed(() => {
  return availablePrompts.value.filter(prompt => prompt.category === 'polish')
})
const optimizeStreamingContent = ref('')
const isOptimizeStreaming = ref(false)

// 新的续写对话框相关数据
const showNewContinueDialog = ref(false)
const continueForm = ref({
  direction: '', // 续写方向
  wordCount: 500, // 续写字数
  isStreaming: false
})
const continueStreamingContent = ref('')
const isContinueStreaming = ref(false)

// 管理数据
const characters = ref([])
// 使用store中的worldSettings
const worldSettings = computed(() => novelStore.worldSettings)
const corpusData = ref([])
const events = ref([])


// 对话框状态
const showCharacterDialog = ref(false)
const showWorldDialog = ref(false)
const showCorpusDialog = ref(false)
const showEventDialog = ref(false)

// 表单数据
const chapterForm = ref({
  title: '',
  description: '',
  status: 'draft'
})

const aiContentForm = ref({
  wordCount: 2000,
  style: 'third-person',
  focus: ''
})

const characterForm = ref({
  id: null,
  name: '',
  role: 'supporting',
  gender: 'male',
  age: 25,
  appearance: '',
  personality: '',
  background: '',
  tags: [],
  avatar: ''
})

const characterTagInput = ref('')

const worldForm = ref({
  id: null,
  title: '',
  description: '',
  category: 'setting',
  details: ''
})

const corpusForm = ref({
  id: null,
  title: '',
  type: 'description',
  content: '',
  tags: []
})

const eventForm = ref({
  id: null,
  title: '',
  description: '',
  chapter: '',
  time: '',
  importance: 'normal'
})

// 编辑器自动滚动到底部
const scrollEditorToBottom = () => {
  nextTick(() => {
    try {
      if (editorRef.value && typeof editorRef.value.scrollToBottom === 'function') {
        editorRef.value.scrollToBottom()
      }
    } catch (error) {
      console.error('编辑器自动滚动失败:', error)
    }
  })
}

// 计算属性
const contentWordCount = computed(() => {
  return content.value.replace(/<[^>]*>/g, '').length
})
// 方法
const goBack = async () => {
  try {
    // 自动保存当前章节
    await saveCurrentChapter()
  } catch (error) {
    console.error('返回时保存章节失败:', error)
    // 即使保存失败也继续导航
  }
  router.push('/novels')
}
const selectChapter = async (chapter) => {
  try {
    // 自动保存当前章节
    await saveCurrentChapter()
    await loadChapter(chapter)
  } catch (error) {
    console.error('切换章节时发生错误:', error)
    // 如果保存失败，仍然尝试加载新章节
    try {
      await loadChapter(chapter)
    } catch (loadError) {
      console.error('加载章节失败:', loadError)
      ElMessage.error('加载章节失败')
    }
  }
}

const loadChapter = async (chapter) => {
  if (!chapter) {
    console.error('loadChapter: 章节对象为空')
    return
  }

  try {
    // 如果有小说ID，从后端加载完整的章节内容
    if (currentNovel.value?.id && chapter.id) {
      try {
        const fullChapter = await chapterApi.getChapter(currentNovel.value.id, chapter.id)
        if (fullChapter) {
          // 使用后端返回的完整数据
          chapter = {
            ...chapter,
            ...fullChapter,
            description: fullChapter.outline || fullChapter.summary || chapter.description || '', // 后端的outline/summary映射到前端的description
            createdAt: fullChapter.createdAt ? new Date(fullChapter.createdAt) : chapter.createdAt,
            updatedAt: fullChapter.updatedAt ? new Date(fullChapter.updatedAt) : chapter.updatedAt
          }

          // 更新本地章节列表中的数据 - 使用直接赋值避免组件更新问题
          if (chapters.value && Array.isArray(chapters.value)) {
            const index = chapters.value.findIndex(c => c && c.id === chapter.id)
            if (index > -1 && chapters.value[index]) {
              // 直接更新对象属性，避免splice引发的组件更新问题
              Object.assign(chapters.value[index], chapter)
            }
          }
        }
      } catch (apiError) {
        console.error('从API加载章节详情失败:', apiError)
        // 如果后端加载失败，使用本地数据
      }
    }

    // 确保章节有正确的状态字段，如果没有则设置为草稿
    if (!chapter.status || chapter.status === 'outline') {
      chapter.status = 'draft'
    }

    // 设置当前章节和内容
    currentChapter.value = chapter
    content.value = chapter.content || ''
  } catch (error) {
    console.error('加载章节过程中发生错误:', error)
    ElMessage.error('加载章节失败，请重试')
    
    // 尝试设置基本内容，避免UI错误
    currentChapter.value = chapter
    content.value = chapter.content || ''
  }
}

const saveCurrentChapter = async () => {
  if (!currentChapter.value || !currentNovel.value?.id) {
    return; // 如果没有当前章节或小说ID，直接返回
  }

  try {
    // 更新本地数据
    currentChapter.value.content = content.value
    currentChapter.value.wordCount = contentWordCount.value
    currentChapter.value.updatedAt = new Date()

    // 同步更新章节列表中的对应数据
    if (chapters.value && Array.isArray(chapters.value) && isComponentMounted.value) {
      const chapterIndex = chapters.value.findIndex(ch => ch && ch.id === currentChapter.value.id)
      if (chapterIndex > -1 && chapters.value[chapterIndex]) {
        const updatedChapter = {
          ...chapters.value[chapterIndex],
          title: currentChapter.value.title,
          description: currentChapter.value.description, // 前端的description对应后端的outline
          content: content.value,
          wordCount: contentWordCount.value,
          status: currentChapter.value.status,
          updatedAt: new Date()
        }
        // 使用splice进行安全的响应式更新
        chapters.value.splice(chapterIndex, 1, updatedChapter)
      }
    }

    // 保存到后端
    const chapterData = {
      title: currentChapter.value.title,
      outline: currentChapter.value.description, // 前端的description对应后端的outline
      content: content.value,
      wordCount: contentWordCount.value,
      status: currentChapter.value.status
    }

    await chapterApi.updateChapter(
        currentNovel.value.id,
        currentChapter.value.id,
        chapterData
    )

  } catch (error) {
    console.error('保存章节内容失败:', error)
    // 即使后端保存失败，也尝试保存到localStorage
  }
}

const addNewChapter = () => {
  editingChapter.value = null
  chapterForm.value = {
    title: '',
    description: '',
    status: 'draft'
  }
  showChapterDialog.value = true
}

const editChapterTitle = (chapter) => {
  editingChapter.value = chapter
  chapterForm.value = {
    title: chapter.title,
    description: chapter.description || '',
    status: chapter.status || 'draft'
  }
  showChapterDialog.value = true
}

const saveChapter = async () => {
  if (!chapterForm.value.title.trim()) {
    ElMessage.warning('请输入章节标题')
    return
  }

  if (!currentNovel.value?.id) {
    ElMessage.error('小说信息不存在')
    return
  }

  try {
    if (editingChapter.value) {
      // 编辑现有章节
      const chapterData = {
        title: chapterForm.value.title,
        outline: chapterForm.value.description, // 前端的description对应后端的outline
        status: chapterForm.value.status,
        content: editingChapter.value.content || '',
        wordCount: editingChapter.value.wordCount || 0
      }

      const updatedChapter = await chapterApi.updateChapter(
          currentNovel.value.id,
          editingChapter.value.id,
          chapterData
      )

      // 更新本地数据
      Object.assign(editingChapter.value, {
        ...updatedChapter,
        description: updatedChapter.outline || updatedChapter.summary || chapterForm.value.description // 确保前端的description字段正确映射
      })

      // 如果这是当前正在编辑的章节，同步更新
      if (currentChapter.value && currentChapter.value.id === editingChapter.value.id) {
        currentChapter.value = { ...editingChapter.value }
      }

      // 同步更新章节列表中的数据
      if (chapters.value && Array.isArray(chapters.value) && isComponentMounted.value) {
        const chapterIndex = chapters.value.findIndex(ch => ch && ch.id === editingChapter.value.id)
        if (chapterIndex > -1 && chapters.value[chapterIndex]) {
          const updatedChapter = {
            ...chapters.value[chapterIndex],
            ...editingChapter.value
          }
          chapters.value.splice(chapterIndex, 1, updatedChapter)
        }
      }

      ElMessage.success('章节信息已更新')
    } else {
      // 新增章节
      const chapterData = {
        title: chapterForm.value.title,
        outline: chapterForm.value.description, // 前端的description对应后端的outline
        status: chapterForm.value.status,
        content: '',
        wordCount: 0
      }

      const newChapter = await chapterApi.createChapter(currentNovel.value.id, chapterData)

      ElMessage.success('章节创建成功')

      // 重新加载当前页的章节数据以保持分页状态
      await loadChaptersWithPagination(
        currentNovel.value.id,
        chapterPagination.value.current,
        chapterPagination.value.size
      )

      // 自动选择新章节
      setTimeout(() => {
        const createdChapter = chapters.value.find(c => c.id === newChapter.id)
        if (createdChapter) {
          selectChapter(createdChapter)
        }
      }, 100)
    }
  } catch (error) {
    console.error('保存章节失败:', error)
    ElMessage.error('保存章节失败: ' + (error.message || '未知错误'))
    return
  }

  showChapterDialog.value = false
}

const deleteChapter = (chapter) => {
  ElMessageBox.confirm(`确定要删除章节《${chapter.title}》吗？`, '确认删除', {
    type: 'warning'
  }).then(async () => {
    if (!currentNovel.value?.id) {
      ElMessage.error('小说信息不存在')
      return
    }

    try {
      // 调用后端API删除章节
      await chapterApi.deleteChapter(currentNovel.value.id, chapter.id)

      // 如果删除的是当前章节，清空编辑器
      if (currentChapter.value?.id === chapter.id) {
        currentChapter.value = null
        content.value = ''
      }

      ElMessage.success('章节已删除')

      // 重新加载当前页的章节数据以保持分页状态
      await loadChaptersWithPagination(
        currentNovel.value.id,
        chapterPagination.value.current,
        chapterPagination.value.size
      )

      // 如果当前页没有章节了，且不是第一页，则跳转到上一页
      if (chapters.value.length === 0 && chapterPagination.value.current > 1) {
        await loadChaptersWithPagination(
          currentNovel.value.id,
          chapterPagination.value.current - 1,
          chapterPagination.value.size
        )
      }

      // 如果还有章节且当前章节被删除了，自动选择第一个章节
      if (chapters.value.length > 0 && !currentChapter.value) {
        setTimeout(() => {
          selectChapter(chapters.value[0])
        }, 100)
      }
    } catch (error) {
      console.error('删除章节失败:', error)
      ElMessage.error('删除章节失败: ' + (error.message || '未知错误'))
    }
  }).catch(() => {})
}

const handleEditorReady = (quill) => {
  try {
    console.log('Quill 编辑器创建成功', quill)
  } catch (error) {
    console.error('编辑器创建失败:', error)
  }
}

// 章节相关方法
const handleChapterCommand = (command) => {
  switch (command) {
    case 'manual':
      addNewChapter()
      break
    case 'ai-single':
      openAISingleChapterDialog()
      break
    case 'ai-batch':
      openAIBatchChapterDialog()
      break
    case 'ai-batch-outline':
      openBatchOutlineGenerateDialog()
      break
  }
}

const handleChapterAction = (command, chapter) => {
  switch (command) {
    case 'edit':
      editChapterTitle(chapter)
      break
    case 'generate':
      openChapterGenerateDialog(chapter)
      break
    case 'generate-outline':
      generateOutlineFromContent(chapter)
      break
    case 'delete':
      deleteChapter(chapter)
      break
  }
}

// 分页相关方法
const loadChaptersWithPagination = async (novelId, page = 1, size = 30) => {
  try {
    chaptersLoading.value = true

    // 调用分页API
    const response = await chapterApi.getChaptersWithPage(novelId, page, size)
    console.log('分页章节数据响应:', response)

    if (response) {
      const pageData = response

      // 更新分页信息
      chapterPagination.value = {
        current: pageData.current || page,
        size: pageData.size || size,
        total: pageData.total || 0
      }

      // 处理章节数据
      const chaptersData = pageData.records || []
      chapters.value = chaptersData.map(chapter => ({
        ...chapter,
        description: chapter.outline || chapter.summary || '',
        createdAt: chapter.createdAt ? new Date(chapter.createdAt) : new Date(),
        updatedAt: chapter.updatedAt ? new Date(chapter.updatedAt) : new Date(),
        status: chapter.status === 'outline' ? 'draft' : (chapter.status || 'draft')
      }))

      console.log('从后端加载分页章节数据:', chapters.value.length, '个章节，总计:', chapterPagination.value.total)
    }
  } catch (error) {
    console.error('加载分页章节数据失败:', error)
    // 如果分页API失败，尝试使用原有API
    try {
      const response = await chapterApi.getChapters(novelId)
      let chaptersData = []

      if (response && response.data) {
        if (Array.isArray(response.data)) {
          chaptersData = response.data
        }
      } else if (response && Array.isArray(response)) {
        chaptersData = response
      }

      // 手动分页
      const total = chaptersData.length
      const startIndex = (page - 1) * size
      const endIndex = startIndex + size
      const paginatedData = chaptersData.slice(startIndex, endIndex)

      chapterPagination.value = {
        current: page,
        size: size,
        total: total
      }

      chapters.value = paginatedData.map(chapter => ({
        ...chapter,
        description: chapter.outline || chapter.summary || '',
        createdAt: chapter.createdAt ? new Date(chapter.createdAt) : new Date(),
        updatedAt: chapter.updatedAt ? new Date(chapter.updatedAt) : new Date(),
        status: chapter.status === 'outline' ? 'draft' : (chapter.status || 'draft')
      }))

      console.log('使用原有API手动分页:', chapters.value.length, '个章节，总计:', total)
    } catch (fallbackError) {
      console.error('章节数据加载完全失败:', fallbackError)
      // 最后尝试从localStorage加载
      const localData = JSON.parse(localStorage.getItem('novels') || '[]')
      const localNovel = localData.find(n => n.id === novelId)
      const localChapters = localNovel?.chapterList || []

      // 手动分页本地数据
      const total = localChapters.length
      const startIndex = (page - 1) * size
      const endIndex = startIndex + size
      const paginatedData = localChapters.slice(startIndex, endIndex)

      chapterPagination.value = {
        current: page,
        size: size,
        total: total
      }

      chapters.value = paginatedData
      ElMessage.warning('章节数据加载失败，使用本地缓存数据')
    }
  } finally {
    chaptersLoading.value = false
  }
}

// 根据章节ID查找并加载对应页面
const loadChapterPage = async (novelId, chapterId) => {
  try {
    chaptersLoading.value = true
    
    // 先尝试获取章节详情来确认章节存在
    const chapterDetail = await chapterApi.getChapter(novelId, chapterId)
    if (!chapterDetail) {
      console.warn('章节不存在:', chapterId)
      // 章节不存在，降级为普通分页加载
      await loadChaptersWithPagination(novelId)
      return
    }
    
    // 计算章节可能在哪一页（这里使用估算方法）
    // 更精确的方法需要后端提供查找章节页码的API
    let foundChapter = false
    let currentPage = 1
    const pageSize = 30
    
    // 最多尝试10页，避免无限循环
    while (currentPage <= 10 && !foundChapter) {
      console.log(`尝试在第${currentPage}页查找章节ID: ${chapterId}`)
      
      const response = await chapterApi.getChaptersWithPage(novelId, currentPage, pageSize)
      
      if (response) {
        const pageData = response
        const chaptersData = pageData.records || []
        
        // 检查当前页是否包含目标章节
        const targetChapter = chaptersData.find(ch => ch.id === chapterId)
        
        if (targetChapter) {
          // 找到目标章节，加载这一页的数据
          console.log(`在第${currentPage}页找到目标章节:`, targetChapter.title)
          
          chapterPagination.value = {
            current: pageData.current || currentPage,
            size: pageData.size || pageSize,
            total: pageData.total || 0
          }
          
          chapters.value = chaptersData.map(chapter => ({
            ...chapter,
            description: chapter.outline || chapter.summary || '',
            createdAt: chapter.createdAt ? new Date(chapter.createdAt) : new Date(),
            updatedAt: chapter.updatedAt ? new Date(chapter.updatedAt) : new Date(),
            status: chapter.status === 'outline' ? 'draft' : (chapter.status || 'draft')
          }))
          
          foundChapter = true
          console.log('成功加载包含目标章节的页面，章节数:', chapters.value.length)
          break
        } else {
          // 当前页没有目标章节，检查是否还有更多页
          const total = pageData.total || 0
          const totalPages = Math.ceil(total / pageSize)
          
          if (currentPage >= totalPages) {
            // 已经是最后一页了，章节不存在
            console.warn('遍历所有页面后未找到章节:', chapterId)
            break
          }
          
          currentPage++
        }
      } else {
        console.error('获取章节页面数据失败')
        break
      }
    }
    
    if (!foundChapter) {
      console.warn('未找到指定章节，使用默认第一页')
      // 降级为普通分页加载
      await loadChaptersWithPagination(novelId)
    }
    
  } catch (error) {
    console.error('查找章节页面失败:', error)
    // 出错时降级为普通分页加载
    await loadChaptersWithPagination(novelId)
  } finally {
    chaptersLoading.value = false
  }
}

const handleChapterPageChange = (page) => {
  if (currentNovel.value) {
    loadChaptersWithPagination(currentNovel.value.id, page, chapterPagination.value.size)
  }
}

const handleChapterSizeChange = (size) => {
  if (currentNovel.value) {
    chapterPagination.value.current = 1 // 重置到第一页
    loadChaptersWithPagination(currentNovel.value.id, 1, size)
  }
}

const getChapterStatusType = (status) => {
  const statusMap = {
    draft: 'warning',
    completed: 'success',
    published: 'primary'
  }
  return statusMap[status] || 'warning'
}

const getChapterStatusText = (status) => {
  const statusMap = {
    draft: '草稿',
    completed: '完成',
    published: '发表'
  }
  return statusMap[status] || '草稿'
}

const getOptimizeTypeText = () => {
  const typeMap = {
    grammar: '语法润色',
    style: '文风优化',
    emotion: '情感增强',
    logic: '逻辑梳理'
  }
  return typeMap[optimizeType.value] || '优化'
}

const getOptimizeInstructions = (type) => {
  const instructions = {
    grammar: `
1. 检查并修正语法错误、错别字、标点符号问题
2. 优化句式结构，使表达更加流畅
3. 保持原文的意思和风格不变
4. 提升文字的准确性和规范性`,
    style: `
1. 优化文字表达，使语言更加优美流畅
2. 增强文字的感染力和表现力
3. 统一文章的语言风格
4. 保持故事情节和人物性格不变`,
    emotion: `
1. 加强情感描写，使情感表达更加深刻
2. 增加心理描写和情感细节
3. 提升读者的情感共鸣
4. 保持情节发展的合理性`,
    logic: `
1. 梳理故事情节的逻辑关系
2. 检查人物行为的合理性
3. 优化情节发展的连贯性
4. 确保时间线和因果关系清晰`
  }
  return instructions[type] || '进行全面优化'
}

// 停止流式生成
const stopStreaming = () => {
  isStreaming.value = false
  isGeneratingContent.value = false
  isGeneratingChapters.value = false
  isOptimizing.value = false
  streamingContent.value = ''
  streamingType.value = ''
  streamingChapter.value = null
  ElMessage.info('已停止AI生成')
}

// 监听流式内容变化，自动滚动到底部
watch(streamingContent, () => {
  if (isStreaming.value) {
    nextTick(() => {
      const streamingContentEl = document.querySelector('.streaming-content')
      if (streamingContentEl) {
        streamingContentEl.scrollTop = streamingContentEl.scrollHeight
      }
    })
  }
})

// 加载提示词数据
const loadPrompts = async () => {
  try {
    const data = await promptApi.getPrompts()
    availablePrompts.value = data || []
    console.log('Writer: 提示词加载成功，数量:', availablePrompts.value.length)
  } catch (error) {
    console.error('Writer: 加载提示词失败:', error)
    ElMessage.warning('加载提示词失败，使用本地数据: ' + error.message)
  }
}


// 根据类型筛选提示词
const getPromptsByCategory = (category) => {
  return availablePrompts.value.filter(prompt => prompt.category === category)
}

// 打开提示词选择对话框
const openPromptDialog = (category) => {
  console.log('openPromptDialog 被调用，category:', category, 'showAIBatchChapterDialog:', showAIBatchChapterDialog.value)

  selectedPromptCategory.value = category
  showPromptDialog.value = true
  selectedPrompt.value = null
  promptVariables.value = {}
  finalPrompt.value = ''

  // 如果是批量章节生成，也需要在这里预处理（虽然还没选择具体提示词）
  if (category === 'outline' && showAIBatchChapterDialog.value) {
    console.log('openPromptDialog: 批量章节生成模式，准备预填充基础变量')
    // 这里不填充具体变量，等用户选择提示词后再填充
  }
}
// 选择提示词
const selectPrompt = (prompt) => {
  selectedPrompt.value = prompt
  promptVariables.value = {}

  // 提取变量
  const matches = prompt.content.match(/\{([^}]+)\}/g)
  if (matches) {
    matches.forEach(match => {
      const variable = match.slice(1, -1)
      promptVariables.value[variable] = ''
    })
  }

  // 如果是批量章节生成，自动填充批量章节变量
  if (selectedPromptCategory.value === 'outline' && showAIBatchChapterDialog.value) {
    console.log('selectPrompt中检测到批量章节生成，调用autoFillBatchChapterVariables')
    // 延迟一下确保变量提取完成
    setTimeout(() => {
      autoFillBatchChapterVariables()
    }, 50)
  }

  // 如果是单章生成，自动填充单章变量
  if (selectedPromptCategory.value === 'outline' && showAISingleChapterDialog.value) {
    console.log('selectPrompt中检测到单章生成，调用autoFillSingleChapterVariables')
    // 延迟一下确保变量提取完成
    setTimeout(() => {
      autoFillSingleChapterVariables()
    }, 50)
  }

  generateFinalPrompt()
}

// 生成最终提示词
const generateFinalPrompt = () => {
  if (!selectedPrompt.value) {
    finalPrompt.value = ''
    return
  }

  let result = selectedPrompt.value.content
  Object.keys(promptVariables.value).forEach(variable => {
    const value = promptVariables.value[variable] || `{${variable}}`
    result = result.replace(new RegExp(`\\{${variable}\\}`, 'g'), value)
  })

  finalPrompt.value = result

  // 如果是批量章节生成，打印调试信息
  if (selectedPromptCategory.value === 'outline' && showAIBatchChapterDialog.value) {
    console.log('generateFinalPrompt - 批量章节生成:', {
      提示词标题: selectedPrompt.value.title,
      已有章节变量值: promptVariables.value['已有章节'] ? promptVariables.value['已有章节'].substring(0, 300) + '...' : '未设置',
      最终提示词包含已有章节: result.includes('已有章节'),
      最终提示词包含章节标题关键词: result.includes('第') && result.includes('章'),
      所有变量: Object.keys(promptVariables.value)
    })
  }
}

// 监听变量变化
watch(promptVariables, () => {
  generateFinalPrompt()
}, { deep: true })

// 监听选中素材变化，自动更新提示词变量
watch(selectedMaterials, () => {
  if (selectedPrompt.value && showChapterGenerateDialog.value) {
    // 重新填充素材相关的变量

    // 填充人物信息
    if (selectedMaterials.value.characters.length > 0) {
      const characterInfo = selectedMaterials.value.characters.map(char =>
          `${char.name}（${char.role}）：${char.personality || '暂无描述'}`
      ).join('\n')
      promptVariables.value['主要人物'] = characterInfo
    } else {
      // 如果没有选中人物，清空人物信息
      if (promptVariables.value['主要人物']) {
        promptVariables.value['主要人物'] = ''
      }
    }

    // 填充世界观信息
    if (selectedMaterials.value.worldSettings.length > 0) {
      const worldInfo = selectedMaterials.value.worldSettings.map(setting =>
          `${setting.title}：${setting.description || '暂无描述'}`
      ).join('\n')
      promptVariables.value['世界观设定'] = worldInfo
    } else {
      // 如果没有选中世界观，清空世界观信息
      if (promptVariables.value['世界观设定']) {
        promptVariables.value['世界观设定'] = ''
      }
    }

    // 填充语料库信息
    if (selectedMaterials.value.corpus.length > 0) {
      const corpusInfo = selectedMaterials.value.corpus.map(item =>
          `【${item.title}】${item.content}`
      ).join('\n\n')
      promptVariables.value['参考语料'] = corpusInfo
    } else {
      // 如果没有选中语料库，清空语料库信息
      if (promptVariables.value['参考语料']) {
        promptVariables.value['参考语料'] = ''
      }
    }

    // 填充选中的章节内容
    if (selectedMaterials.value.chapters.length > 0) {
      const chaptersInfo = selectedMaterials.value.chapters.map(ch => {
        const chapterIndex = getChapterIndex(ch)
        let chapterInfo = `第${chapterIndex}章《${ch.title}》\n`

        if (ch.description) {
          chapterInfo += `章节大纲：${ch.description}\n`
        }

        if (ch.content && ch.content.trim()) {
          // 取章节内容的前500字作为参考，清理HTML标签
          const contentPreview = cleanHtmlForPreview(ch.content, 500)
          chapterInfo += `章节内容：${contentPreview}${ch.content.length > 500 ? '...' : ''}`
        }

        return chapterInfo
      }).join('\n\n')

      promptVariables.value['前文概要'] = chaptersInfo
    } else {
      // 如果没有选中章节，清空前文概要
      if (promptVariables.value['前文概要']) {
        promptVariables.value['前文概要'] = ''
      }
    }

    // 重新生成最终提示词
    generateFinalPrompt()
  }
}, { deep: true })

// 获取分类名称
const getCategoryName = () => {
  const categoryNames = {
    outline: '章节大纲',
    content: '基础正文',
    'content-dialogue': '对话生成',
    'content-scene': '场景描写',
    'content-action': '动作情节',
    'content-psychology': '心理描写',
    polish: '文本优化',
    continue: '智能续写',
    character: '人物生成',
    worldview: '世界观生成'
  }
  return categoryNames[selectedPromptCategory.value] || '提示词'
}

// 重置提示词对话框
const resetPromptDialog = () => {
  selectedPrompt.value = null
  promptVariables.value = {}
  finalPrompt.value = ''
}

// 复制提示词到剪贴板
const copyPromptToClipboard = async () => {
  try {
    await navigator.clipboard.writeText(finalPrompt.value)
    ElMessage.success('提示词已复制到剪贴板')
  } catch (error) {
    ElMessage.error('复制失败')
  }
}

// 跳转到提示词库
const goToPromptLibrary = () => {
  router.push('/prompts')
}

// 使用选中的提示词
const useSelectedPrompt = () => {
  if (!selectedPrompt.value || !finalPrompt.value) {
    ElMessage.warning('请选择提示词并填充变量')
    return
  }

  // 判断当前是什么类型的提示词选择
  if (selectedPromptCategory.value === 'character' && showBatchGenerateCharacterDialog.value) {
    // 批量生成角色提示词
    batchCharacterSelectedPrompt.value = selectedPrompt.value
    batchCharacterPromptVariables.value = { ...promptVariables.value }
    batchCharacterFinalPrompt.value = finalPrompt.value
    showPromptDialog.value = false
    ElMessage.success('已选择批量生成角色提示词')
    return
  }

  if (selectedPromptCategory.value === 'worldview' && showWorldGenerateDialog.value) {
    // 世界观生成提示词
    worldSettingSelectedPrompt.value = selectedPrompt.value
    worldSettingPromptVariables.value = { ...promptVariables.value }
    worldSettingFinalPrompt.value = finalPrompt.value
    showPromptDialog.value = false
    ElMessage.success('已选择世界观生成提示词')
    return
  }

  // 判断是否是单章生成
  if (selectedPromptCategory.value === 'outline' && showAISingleChapterDialog.value) {
    // 单章生成提示词 - 保存提示词信息，不立即生成
    autoFillSingleChapterVariables()

    setTimeout(() => {
      generateFinalPrompt()

      singleChapterSelectedPrompt.value = selectedPrompt.value
      singleChapterPromptVariables.value = { ...promptVariables.value }
      singleChapterFinalPrompt.value = finalPrompt.value

      console.log('保存单章提示词信息:', {
        提示词标题: selectedPrompt.value.title,
        章节标题: aiSingleChapterForm.value.title,
        情节要求: aiSingleChapterForm.value.plotRequirement,
        最终提示词长度: finalPrompt.value.length
      })

      showPromptDialog.value = false
      ElMessage.success('已选择单章生成提示词，请点击"生成章节"按钮开始生成')
    }, 100)

    return
  }

  // 判断是否是批量章节生成
  if (selectedPromptCategory.value === 'outline' && showAIBatchChapterDialog.value) {
    // 批量章节生成提示词 - 确保包含最新的前5章信息
    console.log('确认批量章节提示词，重新填充变量确保包含前5章信息')

    // 重新填充变量确保包含最新的前5章信息
    autoFillBatchChapterVariables()

    // 等一下确保变量填充完成
    setTimeout(() => {
      // 重新生成最终提示词
      generateFinalPrompt()

      // 保存提示词信息
      batchChapterSelectedPrompt.value = selectedPrompt.value
      batchChapterPromptVariables.value = { ...promptVariables.value }
      batchChapterFinalPrompt.value = finalPrompt.value

      console.log('保存批量章节提示词信息:', {
        提示词标题: selectedPrompt.value.title,
        变量数量: Object.keys(promptVariables.value).length,
        已有章节变量: promptVariables.value['已有章节'] ? promptVariables.value['已有章节'].substring(0, 200) + '...' : '未找到',
        最终提示词长度: finalPrompt.value.length,
        最终提示词包含前5章信息: finalPrompt.value.includes('第') && finalPrompt.value.includes('章')
      })

      showPromptDialog.value = false
      ElMessage.success('已选择批量生成章节提示词，请点击"批量生成"按钮开始生成')
    }, 100)

    return
  }

  // 原有的生成操作
  switch (selectedPromptCategory.value) {
    case 'outline':
      generateChaptersWithPrompt(finalPrompt.value)
      break
    case 'content':
      generateContentWithPrompt(finalPrompt.value)
      break
    case 'polish':
      optimizeTextWithPrompt(finalPrompt.value)
      break
    case 'continue':
      continueWritingWithPrompt(finalPrompt.value)
      break
    case 'character':
      generateCharacterWithPrompt(finalPrompt.value)
      break
    case 'worldview':
      // 世界观提示词已在上面的特殊处理中处理
      ElMessage.success('世界观提示词已准备就绪')
      break
    default:
      ElMessage.warning('未知的提示词类型')
      return
  }

  showPromptDialog.value = false
  ElMessage.success('正在使用自定义提示词生成内容...')
}

// 打开章节生成对话框
const openChapterGenerateDialog = (chapter) => {
  targetChapter.value = chapter
  showChapterGenerateDialog.value = true

  // 重置选择的素材
  selectedMaterials.value = {
    characters: [],
    worldSettings: [],
    corpus: [],
    events: [],
    chapters: []
  }

  // 默认选中最近两章内容
  autoSelectRecentTwoChapters()


  // 重置提示词选择
  selectedPrompt.value = null
  promptVariables.value = {}
  finalPrompt.value = ''
}

// 自动填充变量
const autoFillVariables = () => {
  if (!selectedPrompt.value) return

  // 如果是批量章节生成，使用专门的填充函数
  if (showAIBatchChapterDialog.value) {
    autoFillBatchChapterVariables()
    return
  }

  // 正常章节生成需要目标章节
  if (!targetChapter.value) return

  // 自动填充基本信息
  promptVariables.value['小说标题'] = currentNovel.value?.title || '未命名小说'
  promptVariables.value['章节标题'] = targetChapter.value.title || ''
  promptVariables.value['章节大纲'] = targetChapter.value.description || '暂无大纲'

  // 填充人物信息
  if (selectedMaterials.value.characters.length > 0) {
    const characterInfo = selectedMaterials.value.characters.map(char =>
        `${char.name}（${char.role}）：${char.personality || '暂无描述'}`
    ).join('\n')
    promptVariables.value['主要人物'] = characterInfo
  }

  // 填充世界观信息
  if (selectedMaterials.value.worldSettings.length > 0) {
    const worldInfo = selectedMaterials.value.worldSettings.map(setting =>
        `${setting.title}：${setting.description || '暂无描述'}`
    ).join('\n')
    promptVariables.value['世界观设定'] = worldInfo
  }

  // 填充语料库信息
  if (selectedMaterials.value.corpus.length > 0) {
    const corpusInfo = selectedMaterials.value.corpus.map(item =>
        `【${item.title}】${item.content}`
    ).join('\n\n')
    promptVariables.value['参考语料'] = corpusInfo
  }

  // 填充选中的章节内容（使用新的上下文章节选择）
  if (selectedContextChapters.value.length > 0) {
    // 使用用户选择的前文概要章节
    const contextChapters = selectedContextChapters.value.map(chapterId => {
      return chapters.value.find(ch => ch.id === chapterId)
    }).filter(Boolean)

    const contextInfo = contextChapters.map(ch => {
      const chapterIndex = getChapterIndex(ch)
      let chapterInfo = `第${chapterIndex}章《${ch.title}》\n`

      if (ch.description) {
        chapterInfo += `章节大纲：${ch.description}\n`
      }

      if (ch.content && ch.content.trim()) {
        // 取章节内容的前500字作为参考，清理HTML标签
        const contentPreview = cleanHtmlForPreview(ch.content, 500)
        chapterInfo += `章节内容：${contentPreview}${ch.content.length > 500 ? '...' : ''}`
      }

      return chapterInfo
    }).join('\n\n')

    promptVariables.value['前文概要'] = contextInfo
  } else if (targetChapter.value && selectedContextChapters.value.length === 0) {
    // 如果没有选择章节，自动选择最近两章
    autoSelectRecentTwoChapters()
  }

  generateFinalPrompt()
}

// 切换素材选择
const toggleMaterial = (type, material) => {
  const materials = selectedMaterials.value[type]
  const index = materials.findIndex(item => item.id === material.id)

  if (index > -1) {
    // 已选中，取消选择
    materials.splice(index, 1)
  } else {
    // 未选中，添加选择
    materials.push(material)
  }
}

// 为章节选择提示词
const selectPromptForChapter = (prompt) => {
  selectedPrompt.value = prompt
  promptVariables.value = {}

  // 提取变量
  const matches = prompt.content.match(/\{([^}]+)\}/g)
  if (matches) {
    matches.forEach(match => {
      const variable = match.slice(1, -1)
      promptVariables.value[variable] = ''
    })
  }

  // 自动填充变量
  nextTick(() => {
    autoFillVariables()
  })
}


// 获取事件重要性样式
const getImportanceType = (importance) => {
  const typeMap = {
    'high': 'danger',
    'normal': 'primary',
    'low': 'info'
  }
  return typeMap[importance] || 'primary'
}

// 获取可选择的章节列表（排除当前正在生成的章节）
const availableChaptersForSelection = computed(() => {
  if (!chapters.value || !targetChapter.value) return []

  // 只返回当前目标章节之前的章节
  const targetIndex = chapters.value.findIndex(ch => ch.id === targetChapter.value.id)
  if (targetIndex <= 0) return []

  return chapters.value.slice(0, targetIndex).filter(ch => ch.content && ch.content.trim())
})

// 获取可用于前文概要的章节列表（所有有内容的章节，不限制当前章节）
const availableContextChapters = computed(() => {
  if (!chapters.value) return []

  return chapters.value.filter(ch => {
    // 只返回有内容的章节（可以是大纲或正文）
    return ch.description || (ch.content && ch.content.trim())
  }).map(ch => ({
    id: ch.id,
    title: ch.title,
    description: ch.description,
    content: ch.content,
    status: ch.status,
    wordCount: ch.wordCount || 0,
    chapterIndex: getChapterIndex(ch)
  }))
})

// 获取章节索引（第几章）
const getChapterIndex = (chapter) => {
  // 优先使用章节的 chapterOrder 字段，这是章节的真实顺序
  if (chapter.chapterOrder) {
    return chapter.chapterOrder
  }
  // 如果没有 chapterOrder，则使用在当前页面中的位置（分页模式下的临时方案）
  const localIndex = chapters.value.findIndex(ch => ch.id === chapter.id)
  if (localIndex >= 0) {
    return (chapterPagination.value.current - 1) * chapterPagination.value.size + localIndex + 1
  }
  return 1
}

// 清理HTML标签并截取内容预览
const cleanHtmlForPreview = (htmlContent, maxLength = 80) => {
  if (!htmlContent) return ''

  // 去除HTML标签
  let cleanText = htmlContent.replace(/<[^>]*>/g, '')

  // 转换HTML实体
  cleanText = cleanText
      .replace(/&nbsp;/g, ' ')
      .replace(/&lt;/g, '<')
      .replace(/&gt;/g, '>')
      .replace(/&amp;/g, '&')
      .replace(/&quot;/g, '"')
      .replace(/&#39;/g, "'")

  // 去除多余的空白字符
  cleanText = cleanText.replace(/\s+/g, ' ').trim()

  // 截取指定长度
  return cleanText.length > maxLength ? cleanText.substring(0, maxLength) : cleanText
}

// 更新前文概要变量
const updateContextVariable = () => {
  if (selectedContextChapters.value.length > 0) {
    const contextChapters = selectedContextChapters.value.map(chapterId => {
      return chapters.value.find(ch => ch.id === chapterId)
    }).filter(Boolean)

    const contextInfo = contextChapters.map(ch => {
      const chapterIndex = getChapterIndex(ch)
      let chapterInfo = `第${chapterIndex}章《${ch.title}》\n`

      if (ch.description) {
        chapterInfo += `章节大纲：${ch.description}\n`
      }

      if (ch.content && ch.content.trim()) {
        // 取章节内容的前500字作为参考，清理HTML标签
        const contentPreview = cleanHtmlForPreview(ch.content, 500)
        chapterInfo += `章节内容：${contentPreview}${ch.content.length > 500 ? '...' : ''}`
      }

      return chapterInfo
    }).join('\n\n')

    promptVariables.value['前文概要'] = contextInfo
  } else {
    promptVariables.value['前文概要'] = ''
  }

  generateFinalPrompt()
}

// 自动选择最近两章内容
const autoSelectRecentTwoChapters = () => {
  if (!targetChapter.value || !chapters.value.length) {
    selectedContextChapters.value = []
    return
  }

  const targetIndex = chapters.value.findIndex(ch => ch.id === targetChapter.value.id)
  if (targetIndex <= 0) {
    selectedContextChapters.value = []
    return
  }

  // 选择前面最近2章有内容的章节
  const previousChapters = chapters.value.slice(0, targetIndex)
      .filter(ch => ch.description || (ch.content && ch.content.trim()))
      .slice(-2) // 取最近的2章

  selectedContextChapters.value = previousChapters.map(ch => ch.id)
  updateContextVariable()
}

// 清空前文概要选择
const clearContextSelection = () => {
  selectedContextChapters.value = []
  updateContextVariable()
  ElMessage.success('已清空前文概要选择')
}

// 切换上下文章节选择（双向同步）
const toggleContextChapter = (chapterId) => {
  const index = selectedContextChapters.value.indexOf(chapterId)

  if (index > -1) {
    // 已选中，取消选择
    selectedContextChapters.value.splice(index, 1)
  } else {
    // 未选中，添加选择
    selectedContextChapters.value.push(chapterId)
  }

  // 更新前文概要变量
  updateContextVariable()
}

// 选择所有上下文章节
const selectAllContextChapters = () => {
  selectedContextChapters.value = availableContextChapters.value.map(ch => ch.id)
  updateContextVariable()
  ElMessage.success(`已选择所有${availableContextChapters.value.length}个章节`)
}

// 显示批量生成对话框
const showBatchGenerateDialog = () => {
  showBatchGenerateCharacterDialog.value = true
  // 重置配置
  batchGenerateConfig.value = {
    count: 5,
    includeMainCharacters: true,
    includeSupportingCharacters: true,
    includeMinorCharacters: true,
    customPrompt: '',
    autoAssignRoles: true
  }
  batchGenerateResults.value = []
  generatedCharacters.value = []
}

// 批量生成角色
const batchGenerateCharacters = async () => {
  if (!checkApiAndBalance()) return

  batchGenerating.value = true
  batchGenerateResults.value = []
  generatedCharacters.value = []
  streamingContent.value = ''
  isStreaming.value = true
  streamingType.value = 'batchCharacters'

  try {
    let finalPrompt = ''

    // 获取用户配置
    const characterTypes = []
    if (batchGenerateConfig.value.includeMainCharacters) characterTypes.push('主角')
    if (batchGenerateConfig.value.includeSupportingCharacters) characterTypes.push('配角')
    if (batchGenerateConfig.value.includeMinorCharacters) characterTypes.push('次要角色')

    // 如果选择了自定义提示词，融合用户配置
    if (batchCharacterSelectedPrompt.value && batchCharacterFinalPrompt.value) {
      finalPrompt = `=== 小说基本信息 ===
小说标题：${currentNovel.value?.title || '未命名小说'}
小说类型：${(() => {
        const genreMap = {
          'fantasy': '玄幻小说',
          'urban': '都市言情',
          'historical': '历史架空',
          'martial': '武侠修仙',
          'science': '科幻未来',
          'romance': '现代言情',
          'mystery': '悬疑推理',
          'adventure': '冒险奇幻',
          'horror': '恐怖惊悚',
          'general': '通用小说'
        }
        return genreMap[currentNovel.value?.genre] || '通用小说'
      })()}
小说简介：${currentNovel.value?.description || '暂无简介'}

=== 角色生成要求 ===
${batchCharacterFinalPrompt.value}

=== 生成配置 ===
生成数量：${batchGenerateConfig.value.count}个角色
角色类型：${characterTypes.join('、')}

${batchGenerateConfig.value.customPrompt ? `额外要求：${batchGenerateConfig.value.customPrompt}` : ''}

请根据小说信息和以上提示词生成${batchGenerateConfig.value.count}个角色，角色类型应该包括：${characterTypes.join('、')}。确保角色设定符合小说的世界观和风格。`
    } else {
      // 使用默认提示词逻辑
      finalPrompt = `=== 小说基本信息 ===
小说标题：${currentNovel.value?.title || '未命名小说'}
小说类型：${(() => {
        const genreMap = {
          'fantasy': '玄幻小说',
          'urban': '都市言情',
          'historical': '历史架空',
          'martial': '武侠修仙',
          'science': '科幻未来',
          'romance': '现代言情',
          'mystery': '悬疑推理',
          'adventure': '冒险奇幻',
          'horror': '恐怖惊悚',
          'general': '通用小说'
        }
        return genreMap[currentNovel.value?.genre] || '通用小说'
      })()}
小说简介：${currentNovel.value?.description || '暂无简介'}

=== 角色生成任务 ===
你是一个专业的小说角色生成器。请严格按照指定格式为上述小说生成${batchGenerateConfig.value.count}个人物角色。

【重要】必须严格按照以下格式输出，不要添加任何额外的解释或文字：
角色1：
姓名：张三
角色：主角
性别：男
年龄：25
外貌：身高一米八，浓眉大眼，面容坚毅
性格：勇敢正直，有些冲动，但心地善良
背景：出身农家，自幼习武，立志成为英雄
标签：主角,勇敢,正义

角色2：
姓名：李美娜
角色：配角
性别：女
年龄：22
外貌：身材娇小，长发飘逸，眼神清澈动人
性格：温柔善良，聪明机智，偶尔有些任性
背景：大家闺秀，从小接受良好教育，精通琴棋书画
标签：配角,温柔,才女

请完全按照以上示例格式生成${batchGenerateConfig.value.count}个角色，每个角色都必须包含：姓名、角色、性别、年龄、外貌、性格、背景、标签这8个字段。

=== 生成要求 ===
角色类型要求：${characterTypes.join('、')}
${batchGenerateConfig.value.customPrompt ? `特殊要求：${batchGenerateConfig.value.customPrompt}` : ''}

请确保所有角色设定都符合小说的世界观、类型和风格特点。

开始生成：`
    }

    // 为批量角色生成添加强制格式后缀
    const formatSuffix = `

=== 重要格式要求 ===
无论上述提示词如何，你必须严格按照以下格式输出，不得有任何偏差：
请生成${batchGenerateConfig.value.count}个角色，角色类型包括：${characterTypes.join('、')}
角色1：
姓名：[角色姓名]
角色：[主角/配角/反派/次要角色]
性别：[男/女/其他]
年龄：[数字]
外貌：[详细外貌描述]
性格：[性格特点描述]
背景：[背景故事]
标签：[标签1,标签2,标签3]
角色2：
姓名：[角色姓名]
角色：[主角/配角/反派/次要角色]
性别：[男/女/其他]
年龄：[数字]
外貌：[详细外貌描述]
性格：[性格特点描述]
背景：[背景故事]
标签：[标签1,标签2,标签3]
继续按此格式直到生成完所有${batchGenerateConfig.value.count}个角色。每个角色必须包含这8个字段。角色类型应该在${characterTypes.join('、')}中选择。`

    const finalPromptWithFormat = finalPrompt + formatSuffix

    console.log('=== 批量角色生成最终提示词 ===')
    console.log(finalPromptWithFormat)
    console.log('=== 提示词结束 ===')

    const aiResponse = await apiService.generateTextStream(finalPromptWithFormat, {
      maxTokens: null, // 移除token限制
      temperature: 0.8,
      type: 'character'
    }, (chunk, fullContent) => {
      // 实时更新流式内容
      streamingContent.value = fullContent

      // 实时解析角色
      parseGeneratedCharacters(fullContent)

      // 自动滚动到最新内容
      nextTick(() => {
        const streamElement = document.querySelector('.streaming-content')
        if (streamElement) {
          streamElement.scrollTop = streamElement.scrollHeight
        }
      })
    })

    // 最终解析
    parseGeneratedCharacters(aiResponse)

    ElMessage.success(`成功生成 ${generatedCharacters.value.length} 个角色`)
  } catch (error) {
    console.error('批量生成角色失败:', error)
    ElMessage.error(`批量生成失败: ${error.message}`)
  } finally {
    batchGenerating.value = false
    isStreaming.value = false
    streamingContent.value = ''
  }
}
// 解析生成的角色信息
const parseGeneratedCharacters = (content) => {
  if (!content || !content.trim()) {
    generatedCharacters.value = []
    return
  }

  console.log('=== 开始解析角色信息 ===')
  console.log('角色原始内容:', content)
  console.log('内容长度:', content.length)
  console.log('内容前300字符:', content.substring(0, 300))

  // 通用的角色信息提取函数
  const extractCharacterInfo = (text) => {
    const character = {
      id: Date.now() + Math.random() * 1000,
      name: '',
      role: 'supporting',
      gender: 'male',
      age: 25,
      appearance: '',
      personality: '',
      background: '',
      tags: [],
      avatar: '',
      createdAt: new Date(),
      generated: true
    }

    // 提取姓名 - 支持多种格式
    const namePatterns = [
      /(?:姓名|名字|角色名|name)\s*[：:]\s*([^\n\r]+)/i,
      /^([^\n\r：:]{1,10})\s*[：:]?\s*(?:是|为|作为)/,
      /^([^\n\r：:]{2,8})(?:\s|$)/,
    ]

    for (const pattern of namePatterns) {
      const match = text.match(pattern)
      if (match && match[1] && match[1].trim()) {
        character.name = match[1].trim()
        console.log('提取到姓名:', character.name)
        break
      }
    }

    // 提取角色类型
    const rolePatterns = [
      /(?:角色|职责|定位|类型)\s*[：:]\s*([^\n\r]+)/i,
      /(主角|配角|反派|次要角色|男主|女主|反面角色|支持角色)/i
    ]

    for (const pattern of rolePatterns) {
      const match = text.match(pattern)
      if (match && match[1]) {
        const roleText = match[1].trim()
        if (roleText.includes('主角') || roleText.includes('男主') || roleText.includes('女主')) {
          character.role = 'protagonist'
        } else if (roleText.includes('反派') || roleText.includes('反面')) {
          character.role = 'antagonist'
        } else if (roleText.includes('配角') || roleText.includes('支持')) {
          character.role = 'supporting'
        } else {
          character.role = 'minor'
        }
        console.log('提取到角色类型:', character.role)
        break
      }
    }

    // 提取性别
    const genderPatterns = [
      /(?:性别|gender)\s*[：:]\s*([^\n\r]+)/i,
      /(男性|女性|男|女|male|female)/i
    ]

    for (const pattern of genderPatterns) {
      const match = text.match(pattern)
      if (match && match[1]) {
        const genderText = match[1].trim().toLowerCase()
        if (genderText.includes('女') || genderText.includes('female')) {
          character.gender = 'female'
        } else if (genderText.includes('男') || genderText.includes('male')) {
          character.gender = 'male'
        } else {
          character.gender = 'other'
        }
        console.log('提取到性别:', character.gender)
        break
      }
    }

    // 提取年龄
    const agePatterns = [
      /(?:年龄|age)\s*[：:]\s*(\d+)/i,
      /(\d+)\s*(?:岁|years)/i,
      /年龄[约大概]*\s*(\d+)/i
    ]

    for (const pattern of agePatterns) {
      const match = text.match(pattern)
      if (match && match[1]) {
        const age = parseInt(match[1])
        if (!isNaN(age) && age > 0 && age < 200) {
          character.age = age
          console.log('提取到年龄:', character.age)
          break
        }
      }
    }

    // 提取外貌
    const appearancePatterns = [
      /(?:外貌|外观|长相|appearance)\s*[：:]\s*([^\n\r姓名角色性别年龄性格背景标签]+)/i,
      /外貌特征[：:]([^\n\r姓名角色性别年龄性格背景标签]+)/i,
      /长得([^\n\r姓名角色性别年龄性格背景标签]+)/i
    ]

    for (const pattern of appearancePatterns) {
      const match = text.match(pattern)
      if (match && match[1] && match[1].trim()) {
        character.appearance = match[1].trim()
        console.log('提取到外貌:', character.appearance.substring(0, 50))
        break
      }
    }

    // 提取性格
    const personalityPatterns = [
      /(?:性格|个性|personality)\s*[：:]\s*([^\n\r姓名角色性别年龄外貌背景标签]+)/i,
      /性格特点[：:]([^\n\r姓名角色性别年龄外貌背景标签]+)/i,
      /为人([^\n\r姓名角色性别年龄外貌背景标签]+)/i
    ]

    for (const pattern of personalityPatterns) {
      const match = text.match(pattern)
      if (match && match[1] && match[1].trim()) {
        character.personality = match[1].trim()
        console.log('提取到性格:', character.personality.substring(0, 50))
        break
      }
    }

    // 提取背景
    const backgroundPatterns = [
      /(?:背景|经历|身世|background)\s*[：:]\s*([^\n\r姓名角色性别年龄外貌性格标签]+)/i,
      /出身([^\n\r姓名角色性别年龄外貌性格标签]+)/i,
      /来自([^\n\r姓名角色性别年龄外貌性格标签]+)/i
    ]

    for (const pattern of backgroundPatterns) {
      const match = text.match(pattern)
      if (match && match[1] && match[1].trim()) {
        character.background = match[1].trim()
        console.log('提取到背景:', character.background.substring(0, 50))
        break
      }
    }

    // 提取标签
    const tagPatterns = [
      /(?:标签|tags?)\s*[：:]\s*([^\n\r]+)/i,
      /特征[：:]([^\n\r]+)/i
    ]

    for (const pattern of tagPatterns) {
      const match = text.match(pattern)
      if (match && match[1] && match[1].trim()) {
        character.tags = match[1].trim().split(/[,，\s]+/).map(tag => tag.trim()).filter(tag => tag)
        console.log('提取到标签:', character.tags)
        break
      }
    }

    return character
  }

  // 尝试不同的分割方式
  let characterBlocks = []

  // 方式1: 按角色编号分割 (角色1:, 角色2:, etc.)
  if (content.match(/角色\d+[：:]/)) {
    characterBlocks = content.split(/角色\d+[：:]/i).filter(block => block.trim())
    console.log('使用角色编号分割，得到', characterBlocks.length, '个块')
  }
  // 方式2: 按标题分割 (## 标题, # 标题)
  else if (content.match(/#{1,3}\s+/)) {
    characterBlocks = content.split(/#{1,3}\s+/).filter(block => block.trim())
    console.log('使用标题分割，得到', characterBlocks.length, '个块')
  }
  // 方式3: 按数字列表分割 (1., 2., etc.)
  else if (content.match(/^\d+\./m)) {
    characterBlocks = content.split(/^\d+\./m).filter(block => block.trim())
    console.log('使用数字列表分割，得到', characterBlocks.length, '个块')
  }
  // 方式4: 按姓名字段分割
  else if ((content.match(/姓名[：:]/g) || []).length > 1) {
    characterBlocks = content.split(/(?=姓名[：:])/).filter(block => block.trim())
    console.log('使用姓名字段分割，得到', characterBlocks.length, '个块')
  }
  // 方式5: 按空行分割
  else {
    characterBlocks = content.split(/\n\s*\n/).filter(block => block.trim())
    if (characterBlocks.length === 1) {
      // 如果只有一个块，尝试按其他方式分割
      characterBlocks = [content]
    }
    console.log('使用空行分割，得到', characterBlocks.length, '个块')
  }

  characterBlocks.forEach((block, i) => {
    console.log(`块${i}内容:`, block.substring(0, 100) + (block.length > 100 ? '...' : ''))
  })

  const parsed = []

  // 使用新的提取逻辑处理每个块
  characterBlocks.forEach((block, index) => {
    if (!block.trim()) return

    console.log(`=== 处理角色块 ${index} ===`)
    console.log('块内容:', block)

    const character = extractCharacterInfo(block)

    // 如果没有提取到姓名，尝试生成一个
    if (!character.name) {
      // 尝试从第一行提取可能的姓名
      const firstLine = block.split('\n')[0]?.trim()
      if (firstLine && firstLine.length < 20 && !firstLine.includes('：') && !firstLine.includes(':')) {
        character.name = firstLine.replace(/^[^\u4e00-\u9fa5a-zA-Z]*/, '').trim()
      }

      // 如果还是没有姓名，生成默认姓名
      if (!character.name) {
        character.name = `角色${index + 1}`
      }
    }

    // 为空字段提供智能默认值
    if (!character.appearance && (character.personality || character.background)) {
      character.appearance = '外貌特征待补充'
    }
    if (!character.personality && (character.appearance || character.background)) {
      character.personality = '性格特点待补充'
    }
    if (!character.background && (character.appearance || character.personality)) {
      character.background = '背景故事待补充'
    }
    if (character.tags.length === 0) {
      character.tags = [character.role === 'protagonist' ? '主角' : '配角']
    }

    console.log(`最终角色结果 ${index}:`, {
      name: character.name,
      role: character.role,
      gender: character.gender,
      age: character.age,
      appearance: character.appearance?.substring(0, 50) + '...',
      personality: character.personality?.substring(0, 50) + '...',
      background: character.background?.substring(0, 50) + '...',
      tags: character.tags
    })

    // 只要有姓名就添加
    if (character.name && character.name !== '角色') {
      parsed.push(character)
    }
  })

  console.log('角色最终解析结果数量:', parsed.length)
  generatedCharacters.value = parsed
}

// 确认添加生成的角色
const confirmAddGeneratedCharacters = async () => {
  const selectedCharacters = generatedCharacters.value.filter(char => char.selected !== false)

  if (selectedCharacters.length === 0) {
    ElMessage.warning('请选择要添加的角色')
    return
  }

  if (!currentNovel.value?.id) {
    ElMessage.error('小说信息不存在')
    return
  }

  try {
    // 保存角色到后端并添加到本地列表
    const savedCharacters = []
    for (let i = 0; i < selectedCharacters.length; i++) {
      const character = selectedCharacters[i]
      try {
        const characterData = {
          name: character.name,
          role: character.role,
          gender: character.gender,
          age: character.age,
          appearance: character.appearance,
          personality: character.personality,
          background: character.background,
          tags: character.tags || [],
          avatar: character.avatar || '',
          generated: 1 // 标记为AI生成
        }

        const savedCharacter = await characterApi.createCharacter(currentNovel.value.id, characterData)

        // 添加到本地角色列表
        const newCharacter = {
          ...savedCharacter,
          createdAt: new Date(savedCharacter.createdAt),
          updatedAt: new Date(savedCharacter.updatedAt)
        }

        characters.value.push(newCharacter)
        savedCharacters.push(newCharacter)
      } catch (error) {
        console.error(`保存角色 ${character.name} 失败:`, error)
        ElMessage.error(`保存角色"${character.name}"失败: ${error.message}`)
      }
    }


    // 关闭对话框
    showBatchGenerateCharacterDialog.value = false

    if (savedCharacters.length > 0) {
      ElMessage.success(`成功添加 ${savedCharacters.length} 个角色`)
    }
  } catch (error) {
    console.error('批量保存角色失败:', error)
    ElMessage.error('批量保存角色失败: ' + (error.message || '未知错误'))
  }
}

// 切换角色选择状态
const toggleCharacterSelection = (character) => {
  character.selected = character.selected !== false ? false : true
}

// 获取角色类型样式
const getRoleType = (role) => {
  const roleMap = {
    'protagonist': 'danger',
    'supporting': 'primary',
    'antagonist': 'warning',
    'minor': 'info'
  }
  return roleMap[role] || 'info'
}

// 获取角色类型文本
const getRoleText = (role) => {
  const roleMap = {
    'protagonist': '主角',
    'supporting': '配角',
    'antagonist': '反派',
    'minor': '次要角色'
  }
  return roleMap[role] || '配角'
}

// 获取性别文本
const getGenderText = (gender) => {
  const genderMap = {
    'male': '男',
    'female': '女',
    'other': '其他'
  }
  return genderMap[gender] || '男'
}

// 格式化流式内容显示
const formatStreamingContent = (content) => {
  if (!content) return ''

  // 将换行符转换为HTML换行
  let formatted = content.replace(/\n/g, '<br/>')

  // 高亮角色标题
  formatted = formatted.replace(/(角色\d+：)/g, '<strong style="color: #409eff; font-size: 16px;">$1</strong>')

  // 高亮世界观设定标题
  formatted = formatted.replace(/(设定\d+：)/g, '<strong style="color: #409eff; font-size: 16px;">$1</strong>')

  // 高亮字段标签（角色相关）
  formatted = formatted.replace(/(姓名|角色|性别|年龄|外貌|性格|背景|标签)：/g, '<strong style="color: #67c23a;">$1：</strong>')

  // 高亮字段标签（世界观相关）
  formatted = formatted.replace(/(标题|类型|描述)：/g, '<strong style="color: #67c23a;">$1：</strong>')

  return formatted
}

// 获取世界观设定类型样式
const getWorldSettingType = (type) => {
  const typeMap = {
    '地理环境': 'success',
    '文化社会': 'primary',
    '历史背景': 'warning',
    '魔法体系': 'danger',
    '科技水平': 'info',
    '其他': ''
  }
  return typeMap[type] || ''
}

// 显示世界观生成对话框
const openWorldGenerateDialog = () => {
  showWorldGenerateDialog.value = true
  // 重置配置
  worldGenerateConfig.value = {
    count: 3,
    includeGeography: true,
    includeCulture: true,
    includeHistory: true,
    includeMagic: false,
    includeTechnology: false,
    customPrompt: ''
  }
  generatedWorldSettings.value = []
}

// 将英文类型编码转换为中文
const getChineseGenre = (englishGenre) => {
  const genreMap = {
    'fantasy': '玄幻修仙',
    'urban': '都市现代',
    'scifi': '科幻未来',
    'historical': '历史古代',
    'mystery': '悬疑推理',
    'wuxia': '武侠江湖',
    'western-fantasy': '西方奇幻',
    'apocalypse': '末世灾难',
    'romance': '言情小说',
    'military': '军事战争',
    'game': '游戏竞技',
    'business': '商战职场'
  }
  return genreMap[englishGenre] || '通用小说'
}


// AI生成世界观设定
const generateWorldSettings = async () => {
  if (!checkApiAndBalance()) return

  worldGenerating.value = true
  generatedWorldSettings.value = []
  streamingContent.value = ''
  isStreaming.value = true
  streamingType.value = 'worldSettings'

  try {
    let finalPrompt = ''

    // 如果用户选择了自定义提示词，使用自定义提示词
    if (worldSettingSelectedPrompt.value && worldSettingFinalPrompt.value) {
      finalPrompt = `=== 小说基本信息 ===
小说标题：${currentNovel.value?.title || '未命名小说'}
小说类型：${getChineseGenre(currentNovel.value?.genre)}
小说简介：${currentNovel.value?.description || '暂无简介'}

=== 世界观生成要求 ===
${worldSettingFinalPrompt.value}

请根据小说信息和以上要求生成${worldGenerateConfig.value.count}个世界观设定，确保设定符合小说的整体风格和世界观。`
      console.log('使用自定义世界观提示词:', finalPrompt)
    } else {
      // 使用默认的生成逻辑
      const includeTypes = []
      if (worldGenerateConfig.value.includeGeography) includeTypes.push('地理环境')
      if (worldGenerateConfig.value.includeCulture) includeTypes.push('文化社会')
      if (worldGenerateConfig.value.includeHistory) includeTypes.push('历史背景')
      if (worldGenerateConfig.value.includeMagic) includeTypes.push('魔法体系')
      if (worldGenerateConfig.value.includeTechnology) includeTypes.push('科技水平')
      if (worldGenerateConfig.value.includePolitics) includeTypes.push('政治势力')
      if (worldGenerateConfig.value.includeReligion) includeTypes.push('宗教信仰')
      if (worldGenerateConfig.value.includeEconomy) includeTypes.push('经济贸易')
      if (worldGenerateConfig.value.includeRaces) includeTypes.push('种族设定')
      if (worldGenerateConfig.value.includeLanguage) includeTypes.push('语言文字')

      finalPrompt = `=== 小说基本信息 ===
小说标题：${currentNovel.value?.title || '未命名小说'}
小说类型：${getChineseGenre(currentNovel.value?.genre)}
小说简介：${currentNovel.value?.description || '暂无简介'}

=== 世界观生成任务 ===
请为上述小说生成${worldGenerateConfig.value.count}个世界观设定。

=== 生成要求 ===
设定类型要求：${includeTypes.join('、')}
${worldGenerateConfig.value.customPrompt ? `特殊要求：${worldGenerateConfig.value.customPrompt}` : ''}

请为每个设定生成详细信息，格式如下：

设定1：
标题：[设定标题]
类型：[设定类型]
描述：[详细描述，包含具体的设定内容、规则、特点等]

设定2：
...

请确保所有设定都符合小说的类型、风格和世界观，设定之间具有关联性和一致性。`

      console.log('使用默认世界观提示词')
    }

    const aiResponse = await apiService.generateTextStream(finalPrompt, {
      maxTokens: null, // 移除token限制
      temperature: 0.8,
      type: 'worldview'
    }, (chunk, fullContent) => {
      // 实时更新流式内容
      streamingContent.value = fullContent

      // 实时解析世界观设定
      parseGeneratedWorldSettings(fullContent)

      // 自动滚动到最新内容
      nextTick(() => {
        const streamElement = document.querySelector('.streaming-content')
        if (streamElement) {
          streamElement.scrollTop = streamElement.scrollHeight
        }
      })
    })

    // 最终解析
    parseGeneratedWorldSettings(aiResponse)

    ElMessage.success(`成功生成 ${generatedWorldSettings.value.length} 个世界观设定`)
  } catch (error) {
    console.error('AI生成世界观设定失败:', error)
    ElMessage.error(`世界观生成失败: ${error.message}`)
  } finally {
    worldGenerating.value = false
    isStreaming.value = false
    streamingContent.value = ''
  }
}
// 解析生成的世界观设定
const parseGeneratedWorldSettings = (content) => {
  if (!content || !content.trim()) {
    generatedWorldSettings.value = []
    return
  }

  console.log('原始内容:', content)

  // 更灵活的分割方式，支持多种格式
  let settingBlocks = []

  // 尝试不同的分割模式
  if (content.includes('设定1：') || content.includes('设定2：')) {
    // 标准格式：设定1：、设定2：
    settingBlocks = content.split(/设定\d+[：:]/i).filter(block => block.trim())
  } else if (content.includes('## ') || content.includes('# ')) {
    // Markdown格式
    settingBlocks = content.split(/#{1,3}\s+/).filter(block => block.trim())
  } else if (content.includes('1.') || content.includes('2.')) {
    // 列表格式：1. 2. 3.
    settingBlocks = content.split(/\d+\./).filter(block => block.trim())
  } else if (content.includes('**') && content.includes('标题：')) {
    // 包含粗体标记的格式
    settingBlocks = content.split(/\*\*[^*]+\*\*/).filter(block => block.trim())
  } else {
    // 如果没有明确分割符，尝试按连续的"标题："分割
    if (content.split('标题：').length > 2) {
      settingBlocks = content.split('标题：').filter(block => block.trim())
      // 为每个块添加回标题标识符（除了第一个空块）
      settingBlocks = settingBlocks.map((block, index) => {
        if (index === 0 && !block.includes('标题：')) return null // 第一个通常是空的
        return block.includes('标题：') ? block : ('标题：' + block)
      }).filter(block => block !== null)
    } else {
      // 按双换行分割
      const paragraphs = content.split(/\n\s*\n/).filter(p => p.trim())
      if (paragraphs.length > 1) {
        settingBlocks = paragraphs
      } else {
        // 单个大段落
        settingBlocks = [content]
      }
    }
  }

  console.log('分割后的块数:', settingBlocks.length)

  const parsed = []

  settingBlocks.forEach((block, index) => {
    if (!block.trim()) return

    console.log(`处理块 ${index}:`, block.substring(0, 100))

    const lines = block.split('\n').map(line => line.trim()).filter(line => line)
    const setting = {
      id: Date.now() + index * 1000,
      title: '',
      type: '其他',
      description: '',
      createdAt: new Date(),
      generated: true
    }

    let isInDescription = false
    let descriptionParts = []

    lines.forEach((line, lineIndex) => {
      if (line.startsWith('标题：') || line.startsWith('标题:')) {
        setting.title = line.replace(/标题[：:]/, '').trim()
        isInDescription = false
      } else if (line.startsWith('类型：') || line.startsWith('类型:')) {
        setting.type = line.replace(/类型[：:]/, '').trim()
        isInDescription = false
      } else if (line.startsWith('描述：') || line.startsWith('描述:')) {
        // 描述行可能包含内容
        const descriptionContent = line.replace(/描述[：:]/, '').trim()
        if (descriptionContent) {
          descriptionParts = [descriptionContent]
        } else {
          descriptionParts = []
        }
        isInDescription = true
      } else if (isInDescription && line && !line.match(/^(标题|类型|描述)[：:]/)) {
        // 描述的续行（不是其他字段的开始）
        descriptionParts.push(line)
      } else if (!setting.title && lineIndex === 0) {
        // 如果第一行没有"标题："前缀，直接作为标题
        setting.title = line.replace(/^[^\u4e00-\u9fa5a-zA-Z]*/, '').trim()
      } else if (!isInDescription && line && !line.match(/^(标题|类型|描述)[：:]/)) {
        // 如果还没有开始描述部分，且不是特定字段，将其作为描述
        descriptionParts.push(line)
        isInDescription = true
      }
    })

    // 组合描述内容
    if (descriptionParts.length > 0) {
      setting.description = descriptionParts.join('\n').trim()
    }

    // 如果仍然没有标题，尝试从内容中智能提取
    if (!setting.title) {
      if (setting.description && setting.description.length > 0) {
        const firstLine = setting.description.split('\n')[0]
        if (firstLine.length <= 50) {
          setting.title = firstLine
          setting.description = setting.description.split('\n').slice(1).join('\n').trim()
        } else {
          // 尝试从第一句话中提取关键词作为标题
          const firstSentence = firstLine.split(/[。！？.!?]/)[0]
          if (firstSentence.length <= 30) {
            setting.title = firstSentence
          } else {
            setting.title = `世界观设定${index + 1}`
          }
        }
      } else {
        setting.title = `世界观设定${index + 1}`
      }
    }

    // 如果解析失败，尝试将整个块作为一个设定处理
    if (!setting.title && !setting.description) {
      // 将整个块作为描述，从中提取标题
      const blockText = block.trim()
      if (blockText.length > 0) {
        const firstLine = blockText.split('\n')[0].trim()
        if (firstLine.length <= 50 && firstLine.length > 0) {
          setting.title = firstLine
          setting.description = blockText.split('\n').slice(1).join('\n').trim() || '详细设定内容'
        } else {
          setting.title = `世界观设定${index + 1}`
          setting.description = blockText
        }
      }
    }

    // 确保有描述内容
    if (!setting.description || setting.description.trim() === '') {
      setting.description = '暂无描述'
    }

    console.log(`解析结果 ${index}:`, {
      title: setting.title,
      type: setting.type,
      description: setting.description.substring(0, 100) + (setting.description.length > 100 ? '...' : '')
    })

    // 只要有标题就添加设定
    if (setting.title && setting.title.trim() !== '') {
      parsed.push(setting)
    }
  })

  // 如果没有解析到任何设定，但有内容，创建一个默认设定
  if (parsed.length === 0 && content.trim().length > 0) {
    const lines = content.trim().split('\n').filter(line => line.trim())
    if (lines.length > 0) {
      const defaultSetting = {
        id: Date.now(),
        title: lines[0].length <= 50 ? lines[0] : '世界观设定',
        type: '其他',
        description: lines.length > 1 ? lines.slice(1).join('\n') : lines[0],
        createdAt: new Date(),
        generated: true
      }
      parsed.push(defaultSetting)
      console.log('创建默认设定:', defaultSetting)
    }
  }

  console.log('最终解析结果数量:', parsed.length)
  generatedWorldSettings.value = parsed
}
// 确认添加生成的世界观设定
const confirmAddGeneratedWorldSettings = async () => {
  const selectedSettings = generatedWorldSettings.value.filter(setting => setting.selected !== false)

  if (selectedSettings.length === 0) {
    ElMessage.warning('请选择要添加的世界观设定')
    return
  }

  if (!currentNovel.value?.id) {
    ElMessage.error('小说信息不存在')
    return
  }

  try {
    // 保存世界观设定到后端并添加到store中
    const savedSettings = []
    for (let i = 0; i < selectedSettings.length; i++) {
      const setting = selectedSettings[i]
      try {
        const worldSettingData = {
          title: setting.title,
          description: setting.description,
          category: setting.category || 'setting',
          details: setting.details || ''
        }

        const savedWorldSetting = await worldSettingApi.createWorldSetting(currentNovel.value.id, worldSettingData)

        // 添加到store中
        novelStore.addWorldSetting({
          ...savedWorldSetting,
          createdAt: new Date(savedWorldSetting.createdAt),
          updatedAt: new Date(savedWorldSetting.updatedAt)
        })

        savedSettings.push(savedWorldSetting)
      } catch (error) {
        console.error(`保存世界观设定 ${setting.title} 失败:`, error)
        ElMessage.error(`保存世界观设定"${setting.title}"失败: ${error.message}`)
      }
    }


    // 关闭对话框
    showWorldGenerateDialog.value = false

    if (savedSettings.length > 0) {
      ElMessage.success(`成功添加 ${savedSettings.length} 个世界观设定`)
    }
  } catch (error) {
    console.error('批量保存世界观设定失败:', error)
    ElMessage.error('批量保存世界观设定失败: ' + (error.message || '未知错误'))
  }
}
// AI生成单个世界观设定描述
const generateWorldSettingAI = async () => {
  if (!checkApiAndBalance()) return

  if (!worldForm.value.title?.trim()) {
    ElMessage.warning('请先输入设定标题')
    return
  }

  isGeneratingWorldSetting.value = true
  streamingContent.value = ''
  isStreaming.value = true
  streamingType.value = 'worldSetting'

  // 清空描述字段，准备接收生成内容
  worldForm.value.description = ''

  try {
    const categoryText = {
      'setting': '世界设定',
      'magic': '魔法体系',
      'politics': '政治势力',
      'geography': '地理环境',
      'history': '历史背景'
    }[worldForm.value.category] || '世界设定'

    const prompt = `=== 小说基本信息 ===
小说标题：${currentNovel.value?.title || '未命名小说'}
小说类型：${(() => {
      const genreMap = {
        'fantasy': '玄幻小说',
        'urban': '都市言情',
        'historical': '历史架空',
        'martial': '武侠修仙',
        'science': '科幻未来',
        'romance': '现代言情',
        'mystery': '悬疑推理',
        'adventure': '冒险奇幻',
        'horror': '恐怖惊悚',
        'general': '通用小说'
      }
      return genreMap[currentNovel.value?.genre] || '通用小说'
    })()}
小说简介：${currentNovel.value?.description || '暂无简介'}

=== 世界观设定生成任务 ===
请为上述小说生成世界观设定的详细描述。

=== 设定信息 ===
- 设定标题：${worldForm.value.title}
- 设定类别：${categoryText}

=== 生成要求 ===
请生成详细的设定描述，包括：
1. 具体的设定内容和规则
2. 在小说世界中的作用和意义
3. 与其他设定的关联性
4. 对故事情节的影响

要求描述详细、生动，符合小说的类型、风格和整体世界观。`

    const aiResponse = await apiService.generateTextStream(prompt, {
      maxTokens: null, // 移除token限制
      temperature: 0.8,
      type: 'worldview'
    }, (chunk, fullContent) => {
      // 实时更新流式内容
      streamingContent.value = fullContent

      // 实时更新表单字段
      worldForm.value.description = fullContent
    })

    // 最终更新
    worldForm.value.description = aiResponse

    ElMessage.success('AI世界观设定生成完成')
  } catch (error) {
    console.error('AI生成世界观设定失败:', error)
    ElMessage.error(`设定生成失败: ${error.message}`)
  } finally {
    isGeneratingWorldSetting.value = false
    isStreaming.value = false
    streamingContent.value = ''
  }
}

// 使用自定义提示词生成章节
const generateChaptersWithPrompt = async (customPrompt) => {
  if (!checkApiAndBalance()) return

  isGeneratingChapters.value = true
  isStreaming.value = true
  streamingType.value = 'chapter'
  streamingContent.value = ''

  try {
    console.log('使用自定义提示词生成章节:', customPrompt)

    // 在自定义提示词前添加小说基本信息
    const promptWithNovelInfo = `=== 小说基本信息 ===
小说标题：${currentNovel.value?.title || '未命名小说'}
小说类型：${(() => {
      const genreMap = {
        'fantasy': '玄幻小说',
        'urban': '都市言情',
        'historical': '历史架空',
        'martial': '武侠修仙',
        'science': '科幻未来',
        'romance': '现代言情',
        'mystery': '悬疑推理',
        'adventure': '冒险奇幻',
        'horror': '恐怖惊悚',
        'general': '通用小说'
      }
      return genreMap[currentNovel.value?.genre] || '通用小说'
    })()}
小说简介：${currentNovel.value?.description || '暂无简介'}

=== 章节生成要求 ===
${customPrompt}

请确保生成的章节符合小说的整体风格、类型和世界观设定。`

    const aiResponse = await apiService.generateTextStream(promptWithNovelInfo, {
      maxTokens: null, // 移除token限制
      temperature: 0.8,
      type: 'outline'
    }, (chunk, fullContent) => {
      streamingContent.value = fullContent
    })

    if (!aiResponse.trim()) {
      throw new Error('AI返回内容为空')
    }

    // 解析AI响应，提取章节信息
    const newChapters = parseChapterResponse(aiResponse)

    // 保存章节到后端并添加到本地列表
    const savedChapters = []
    for (let index = 0; index < newChapters.length; index++) {
      const chapterData = newChapters[index]
      try {
        const chapterToSave = {
          title: chapterData.title || `AI生成章节 ${chapters.value.length + index + 1}`,
          outline: chapterData.description || chapterData.outline || '暂无描述', // 前端的description对应后端的outline
          content: '',
          wordCount: 0,
          status: 'draft'
        }

        const savedChapter = await chapterApi.createChapter(currentNovel.value.id, chapterToSave)

        // 添加到本地章节列表
        const newChapter = {
          ...savedChapter,
          description: savedChapter.outline || savedChapter.summary || '', // 后端的outline映射到前端的description
          createdAt: new Date(savedChapter.createdAt),
          updatedAt: new Date(savedChapter.updatedAt)
        }

        chapters.value.push(newChapter)
        savedChapters.push(newChapter)
      } catch (error) {
        console.error(`保存章节 ${index + 1} 失败:`, error)
        ElMessage.error(`保存章节"${chapterData.title}"失败: ${error.message}`)
      }
    }

    if (savedChapters.length > 0) {
      ElMessage.success(`成功生成并保存${savedChapters.length}个章节大纲`)
    }
  } catch (error) {
    console.error('AI生成章节失败:', error)
    ElMessage.error(`章节生成失败: ${error.message}`)
  } finally {
    isGeneratingChapters.value = false
    isStreaming.value = false
    streamingContent.value = ''
  }
}

// 使用自定义提示词生成正文
const generateContentWithPrompt = async (customPrompt) => {
  if (!checkApiAndBalance()) return

  if (!currentChapter.value) {
    ElMessage.warning('请先选择一个章节')
    return
  }

  isGeneratingContent.value = true
  isStreaming.value = true
  streamingType.value = 'content'
  streamingContent.value = ''
  streamingChapter.value = currentChapter.value

  try {
    console.log('使用自定义提示词生成正文:', customPrompt)

    // 构建完整的生成上下文，确保故事一致性和连贯性
    const context = buildGenerationContext()


    // 构建完整的提示词，包含小说信息、配置和自定义提示词
    let promptWithNovelInfo = `=== 小说基本信息 ===
小说标题：${currentNovel.value?.title || '未命名小说'}
小说类型：${(() => {
      const genreMap = {
        'fantasy': '玄幻小说',
        'urban': '都市言情',
        'historical': '历史架空',
        'martial': '武侠修仙',
        'science': '科幻未来',
        'romance': '现代言情',
        'mystery': '悬疑推理',
        'adventure': '冒险奇幻',
        'horror': '恐怖惊悚',
        'general': '通用小说'
      }
      return genreMap[currentNovel.value?.genre] || '通用小说'
    })()}
小说简介：${currentNovel.value?.description || '暂无简介'}

=== 当前章节信息 ===
章节标题：${currentChapter.value.title}
章节大纲：${currentChapter.value.description || '暂无大纲'}
`

    // 添加人物信息（如果用户选择了人物素材）
    if (selectedMaterials.value.characters.length > 0) {
      const charactersToUse = selectedMaterials.value.characters
      promptWithNovelInfo += `=== 主要人物设定 ===
${charactersToUse.map(char =>
          `- ${char.name}（${char.role}）：${char.personality || '暂无描述'}`
      ).join('\n')}

`
    }

    // 添加世界观信息（如果用户选择了世界观素材）
    if (selectedMaterials.value.worldSettings.length > 0) {
      const worldSettingsToUse = selectedMaterials.value.worldSettings
      promptWithNovelInfo += `=== 世界观设定 ===
${worldSettingsToUse.map(setting =>
          `- ${setting.title}：${setting.description || '暂无描述'}`
      ).join('\n')}

`
    }

    // 添加语料库信息（如果用户选择了语料库素材）
    if (selectedMaterials.value.corpus.length > 0) {
      promptWithNovelInfo += `=== 参考语料 ===
${selectedMaterials.value.corpus.map(item =>
          `【${item.title}】${item.content}`
      ).join('\n\n')}

`
    }

    // 添加事件线信息（如果用户选择了事件素材）
    if (selectedMaterials.value.events.length > 0) {
      const eventsToUse = selectedMaterials.value.events
      promptWithNovelInfo += `=== 相关事件线 ===
${eventsToUse.map(event =>
          `- 第${event.chapter}章：${event.title} - ${event.description || '暂无描述'}`
      ).join('\n')}

【事件线要求】本章内容需要考虑以上事件的影响和发展，确保情节的连贯性和合理性。

`
    }

    // 添加前文上下文（优先使用用户选择的上下文章节）
    let selectedChapters = []

    // 如果用户在对话框中选择了特定的上下文章节，使用这些章节
    if (selectedContextChapters.value && selectedContextChapters.value.length > 0) {
      selectedChapters = selectedContextChapters.value.map(chapterId => {
        return chapters.value.find(ch => ch.id === chapterId)
      }).filter(Boolean)
    }

    if (selectedChapters.length > 0) {
      // 显示使用的上下文章节信息
      const chapterNames = selectedChapters.map(ch => {
        const chapterIndex = chapters.value.findIndex(c => c.id === ch.id) + 1
        return `第${chapterIndex}章：${ch.title}`
      }).join('、')

      console.log(`正在使用以下章节作为上下文参考：${chapterNames}`)
      ElMessage.info({
        message: `使用上下文：${chapterNames}`,
        duration: 3000
      })

      promptWithNovelInfo += `=== 前文概要（必须保持连贯） ===
${selectedChapters.map((ch) => {
        const chapterIndex = chapters.value.findIndex(c => c.id === ch.id) + 1
        return `第${chapterIndex}章《${ch.title}》：${ch.description || '暂无概要'}`
      }).join('\n')}

=== 前文详细内容（保持文风和情节连贯） ===`

      // 获取选中章节的实际内容，特别是结尾部分
      selectedChapters.forEach((ch) => {
        const chapterIndex = chapters.value.findIndex(c => c.id === ch.id) + 1
        if (ch.description) {
          promptWithNovelInfo += `
【第${chapterIndex}章大纲】
${ch.description}
`
        }

        if (ch.content && ch.content.trim()) {
          // 提取章节内容的前500字和后500字作为参考
          const content = ch.content.replace(/<[^>]*>/g, '').trim() // 去除HTML标签

          if (content.length <= 1000) {
            // 如果内容不长，直接包含全部
            promptWithNovelInfo += `
【第${chapterIndex}章内容】
${content}
`
          }
        }
      })

      promptWithNovelInfo += `
【重要】必须确保本章内容与选定的前文章节在以下方面保持连贯：
- 人物性格和行为逻辑一致
- 时间线和事件发展合理
- 情节推进自然流畅
- 世界观设定保持统一
- 文风和叙述风格保持一致
- 与前文情节自然衔接，特别是与最后章节的结尾部分

`
    }

    // 添加用户的自定义提示词作为核心生成要求
    promptWithNovelInfo += `=== 核心生成要求 ===
${customPrompt}

=== 写作要求（必须严格遵守） ===
1. 严格按照章节大纲发展情节，不得偏离主线剧情
2. 与前文内容保持逻辑连贯，人物行为符合已建立的性格
3. 世界观、人物设定、时间线必须与前文保持一致
4. 确保本章有明确的开始、发展、高潮、结尾

=== 人设要求 ===
你是一个小说写作高手，擅长写作引人入胜，让读者情绪波动起伏的小说，受众对象是中学生等文化水平不高的人群，语言风格多变有创造性，被人誉为“鬼才”。

=== 质量标准 ===
1. 情节发展必须合理，不出现逻辑漏洞
2. 人物对话符合各自的性格特点
3. 环境描写与已建立的世界观一致
4. 节奏控制得当，张弛有度
5. 语言风格与整部小说保持统一
7. 不要询问用户是否继续，一次性直接输出全部正文，不要输出其他内容

【警告】绝对不能：
- 偏离章节大纲的主要情节
- 改变已确定的人物性格
- 违背已建立的世界观设定
- 出现与前文矛盾的内容

请确保生成的正文符合小说的整体风格、类型和世界观设定，与章节大纲保持一致。`

    console.log('=== 发送给AI的完整提示词 ===')
    console.log('选中的上下文章节:', selectedChapters.map(ch => `第${chapters.value.findIndex(c => c.id === ch.id) + 1}章：${ch.title}`))
    console.log(promptWithNovelInfo)
    console.log('=== 提示词结束 ===')

    const aiResponse = await apiService.generateTextStream(promptWithNovelInfo, {
      maxTokens: null, // 移除token限制
      temperature: 0.8,
      type: 'generation'
    }, (chunk, fullContent) => {
      console.log('提示词生成流式回调:', chunk.length, '字符，总长度:', fullContent.length)

      // 更新流式显示内容（原始内容，用于流式显示）
      streamingContent.value = fullContent

      // 格式化内容用于编辑器
      const formattedContent = formatGeneratedContent(fullContent, currentChapter.value.title)

      if (streamingChapter.value?.id === currentChapter.value?.id) {
        content.value = formattedContent
        hasUnsavedChanges.value = true
        
        // 自动滚动编辑器到底部
        scrollEditorToBottom()
      }
    })

    if (!aiResponse.trim()) {
      throw new Error('AI返回内容为空')
    }

    const formattedContent = formatGeneratedContent(aiResponse, currentChapter.value.title)
    content.value = formattedContent
    hasUnsavedChanges.value = true
    currentChapter.value.status = 'draft'

    ElMessage.success('正文生成成功')

    setTimeout(() => {
      saveCurrentChapter()
    }, 1000)

  } catch (error) {
    console.error('AI生成正文失败:', error)
    ElMessage.error(`正文生成失败: ${error.message}`)
  } finally {
    isGeneratingContent.value = false
    isStreaming.value = false
    streamingContent.value = ''
    streamingChapter.value = null
  }
}

// 使用自定义提示词优化文本
const optimizeTextWithPrompt = async (customPrompt = null) => {
  if (!checkApiAndBalance()) return

  if (!currentChapter.value || !content.value) {
    ElMessage.warning('请先选择章节并添加内容')
    return
  }

  isOptimizing.value = true
  isStreaming.value = true
  streamingType.value = 'optimize'
  streamingContent.value = ''
  streamingChapter.value = currentChapter.value

  try {
    let promptToUse = customPrompt

    // 如果没有提供自定义提示词，使用弹窗中的配置
    if (!customPrompt) {
      if (optimizeSelectedPrompt.value) {
        promptToUse = optimizeFinalPrompt.value
      } else {
        // 使用默认优化提示词
        promptToUse = getDefaultOptimizePrompt()
      }
    }

    // 在自定义提示词前添加小说基本信息
    const promptWithNovelInfo = `=== 小说基本信息 ===
小说标题：${currentNovel.value?.title || '未命名小说'}
小说类型：${(() => {
      const genreMap = {
        'fantasy': '玄幻小说',
        'urban': '都市言情',
        'historical': '历史架空',
        'martial': '武侠修仙',
        'science': '科幻未来',
        'romance': '现代言情',
        'mystery': '悬疑推理',
        'adventure': '冒险奇幻',
        'horror': '恐怖惊悚',
        'general': '通用小说'
      }
      return genreMap[currentNovel.value?.genre] || '通用小说'
    })()}
小说简介：${currentNovel.value?.description || '暂无简介'}

=== 当前章节信息 ===
章节标题：${currentChapter.value.title}
章节大纲：${currentChapter.value.description || '暂无大纲'}

=== 优化要求 ===
${promptToUse}

=== 原文内容 ===
${getCurrentTextForOptimization()}

请确保优化后的内容符合小说的整体风格、类型和世界观设定。`

    const optimizedContent = await apiService.generateTextStream(promptWithNovelInfo, {
      maxTokens: null, // 移除token限制
      temperature: 0.7,
      type: 'optimize'
    }, (chunk, fullContent) => {
      console.log('优化流式回调:', chunk.length, '字符，总长度:', fullContent.length)
      streamingContent.value = fullContent
    })

    content.value = optimizedContent
    hasUnsavedChanges.value = true
    ElMessage.success('文本优化完成')

    // 关闭弹窗
    showOptimizePromptDialog.value = false

    setTimeout(() => {
      saveCurrentChapter()
    }, 1000)

  } catch (error) {
    console.error('文本优化失败:', error)
    ElMessage.error(`优化失败: ${error.message}`)
  } finally {
    isOptimizing.value = false
    isStreaming.value = false
  }
}




const getCurrentTextForOptimization = () => {
  if (!content.value) return ''

  // 移除HTML标签，获取纯文本
  const textContent = content.value.replace(/<[^>]*>/g, '').trim()

  // 如果有选中的文本，优先使用选中的文本
  // 这里可以根据实际需求实现文本选择逻辑
  return textContent
}




const getDefaultOptimizePrompt = () => {
  const instructions = getOptimizeInstructions(optimizeType.value)
  return `请对以下小说内容进行${getOptimizeTypeText()}。

优化要求：
${instructions}

请返回优化后的内容，保持原文的故事情节和人物性格不变。`
}
// 使用自定义提示词续写
const continueWritingWithPrompt = async (customPrompt) => {
  if (!checkApiAndBalance()) return

  if (!currentChapter.value) {
    ElMessage.warning('请先选择一个章节')
    return
  }

  if (!content.value || content.value.trim().length < 50) {
    ElMessage.warning('请先写一些内容，AI将基于现有内容进行续写')
    return
  }

  isGeneratingContent.value = true
  isStreaming.value = true
  streamingType.value = 'continue'
  streamingContent.value = ''
  streamingChapter.value = currentChapter.value

  const originalContent = content.value

  try {
    console.log('使用自定义提示词续写:', customPrompt)

    // 构建完整的生成上下文
    const context = buildGenerationContext()
    const settings = aiContentForm.value

    // 在自定义提示词前添加完整的配置信息
    let promptWithNovelInfo = `=== 小说基本信息 ===
小说标题：${currentNovel.value?.title || '未命名小说'}
小说类型：${(() => {
      const genreMap = {
        'fantasy': '玄幻小说',
        'urban': '都市言情',
        'historical': '历史架空',
        'martial': '武侠修仙',
        'science': '科幻未来',
        'romance': '现代言情',
        'mystery': '悬疑推理',
        'adventure': '冒险奇幻',
        'horror': '恐怖惊悚',
        'general': '通用小说'
      }
      return genreMap[currentNovel.value?.genre] || '通用小说'
    })()}
小说简介：${currentNovel.value?.description || '暂无简介'}

=== 当前章节信息 ===
章节标题：${currentChapter.value.title}
章节大纲：${currentChapter.value.description || '暂无大纲'}

=== 生成配置 ===
生成类型：${getContentCategoryDescription(selectedContentCategory.value)}
重点内容：${settings.focus || '按大纲发展'}

`

    // 添加人物信息
    if (context.characters.length > 0 && settings.useCharacters) {
      promptWithNovelInfo += `=== 主要人物设定 ===
${context.characters.map(char =>
          `- ${char.name}（${char.role}）：${char.personality || '暂无描述'}`
      ).join('\n')}

`
    }

    // 添加世界观信息
    if (context.worldSettings.length > 0 && settings.useWorldview) {
      promptWithNovelInfo += `=== 世界观设定 ===
${context.worldSettings.map(setting =>
          `- ${setting.title}：${setting.description || '暂无描述'}`
      ).join('\n')}

`
    }

    promptWithNovelInfo += `=== 已有内容（必须保持连贯） ===
${originalContent}

=== 续写要求 ===
${customPrompt}

=== 核心约束（必须严格遵守） ===
1. 【连贯性】必须与已有内容在语言风格、情节发展、人物行为上完全连贯
2. 【一致性】人物性格、世界观设定、时间线必须与前文保持一致
3. 【逻辑性】情节发展必须符合逻辑，不能出现突兀的转折
4. 【主题控制】不得偏离章节大纲的主要情节线

=== 写作要求 ===
1. 基于已有内容的风格和语调继续创作
2. 保持${getViewpointDescription(settings.style)}的叙述方式
3. 保持情节的连贯性和逻辑性
4. 符合章节大纲的发展方向
5. 根据生成类型重点突出：${getContentCategoryGuidance(selectedContentCategory.value)}
6. 突出重点：${settings.focus || '按大纲推进剧情'}

=== 质量标准 ===
1. 续写内容与前文无缝衔接，读者感受不到断层
2. 人物对话和行为符合已建立的性格特点
3. 情节推进自然流畅，不出现逻辑跳跃
4. 语言风格与前文完全一致

【警告】绝对不能：
- 改变已有内容中人物的性格特点
- 违背已建立的情节设定
- 出现与前文矛盾的描述
- 偏离章节大纲的发展方向

请确保续写内容符合小说的整体风格、类型和世界观设定，与前文保持完美连贯性。`

    const aiResponse = await apiService.generateTextStream(promptWithNovelInfo, {
      maxTokens: null, // 移除token限制
      temperature: 0.8,
      type: 'continue'
    }, (chunk, fullContent) => {
      const formattedContent = formatGeneratedContent(fullContent, '')
      streamingContent.value = formattedContent

      if (streamingChapter.value?.id === currentChapter.value?.id) {
        content.value = originalContent + '\n' + formattedContent
        hasUnsavedChanges.value = true
        
        // 自动滚动编辑器到底部
        scrollEditorToBottom()
      }
    })

    if (!aiResponse.trim()) {
      throw new Error('AI返回内容为空')
    }

    const formattedContent = formatGeneratedContent(aiResponse, '')
    content.value = originalContent + '\n' + formattedContent
    hasUnsavedChanges.value = true

    ElMessage.success('续写完成')

    setTimeout(() => {
      saveCurrentChapter()
    }, 1000)

  } catch (error) {
    console.error('AI续写失败:', error)
    ElMessage.error(`续写失败: ${error.message}`)
    content.value = originalContent
  } finally {
    isGeneratingContent.value = false
    isStreaming.value = false
    streamingContent.value = ''
    streamingChapter.value = null
  }
}

// 切换世界观设定选择状态
const toggleWorldSettingSelection = (setting) => {
  setting.selected = setting.selected !== false ? false : true
}

// 处理 ChapterGenerateDialog 组件的生成事件
const handleChapterGenerate = async (data) => {
  if (!currentChapter.value) {
    ElMessage.warning('请先选择要生成内容的章节')
    return
  }

  if (!checkApiAndBalance()) return

  isGeneratingContent.value = true
  showChapterGenerateDialog.value = false

  try {
    await generateContentWithPrompt(data.prompt)
  } catch (error) {
    console.error('生成失败:', error)
    ElMessage.error('生成失败: ' + error.message)
  } finally {
    isGeneratingContent.value = false
  }
}
const generateChapterContentWithDialog = async () => {
  if (!selectedPrompt.value) {
    ElMessage.warning('请先选择提示词模板')
    return
  }

  if (!currentChapter.value) {
    ElMessage.warning('请先选择要生成内容的章节')
    return
  }

  if (!checkApiAndBalance()) return

  isGeneratingContent.value = true
  showChapterGenerateDialog.value = false

  try {
    await generateContentWithPrompt(finalPrompt.value)
  } catch (error) {
    console.error('生成失败:', error)
    ElMessage.error('生成失败: ' + error.message)
  } finally {
    isGeneratingContent.value = false
  }
}

const generateChapterOutline = async () => {
  if (!checkApiAndBalance()) return

  isGeneratingOutline.value = true
  try {
    const chapterTitle = chapterForm.value.title || '新章节'
    const context = buildGenerationContext()

    const prompt = `=== 小说基本信息 ===
小说标题：${currentNovel.value?.title || '未命名小说'}
小说类型：${(() => {
      const genreMap = {
        'fantasy': '玄幻小说',
        'urban': '都市言情',
        'historical': '历史架空',
        'martial': '武侠修仙',
        'science': '科幻未来',
        'romance': '现代言情',
        'mystery': '悬疑推理',
        'adventure': '冒险奇幻',
        'horror': '恐怖惊悚',
        'general': '通用小说'
      }
      return genreMap[currentNovel.value?.genre] || '通用小说'
    })()}
小说简介：${currentNovel.value?.description || '暂无简介'}

=== 章节简介生成任务 ===
请为上述小说的章节《${chapterTitle}》生成章节简介。

章节标题：${chapterTitle}

${context.characters.length > 0 ? `主要人物：
${context.characters.map(char => `- ${char.name}（${char.role}）`).join('\n')}` : ''}

${context.worldSettings.length > 0 ? `世界观设定：
${context.worldSettings.map(setting => `- ${setting.title}`).join('\n')}` : ''}

已有章节：
${chapters.value.map((ch, idx) => `第${idx + 1}章：${ch.title} - ${ch.description || '暂无描述'}`).join('\n')}

=== 核心约束（必须严格遵守） ===
1. 【主题控制】大纲必须服务于小说的主线剧情，不得偏离主题
2. 【连贯性】与前文章节在情节、人物、世界观上保持完全连贯
3. 【逻辑性】情节发展必须符合逻辑，人物行为合理
4. 【完整性】确保章节有明确的目标和完整的结构

=== 大纲生成要求 ===
1. 生成该章节的详细内容大纲
2. 包含具体的情节发展和转折点
3. 标明重要的人物出场和互动
4. 设计关键的场景和冲突
5. 安排章节的起承转合
6. 明确章节在整体故事中的作用

=== 质量标准 ===
1. 大纲内容与小说主题高度契合
2. 情节发展自然流畅，无逻辑漏洞
3. 人物行为符合已建立的性格特点
4. 与前文章节形成有机整体

【警告】绝对不能：
- 偏离小说的主线剧情
- 违背已建立的世界观设定
- 出现与前文矛盾的情节
- 设计不符合人物性格的行为

请生成章节简介，不超过300字：`

    console.log('开始AI生成章节简介:', prompt)

    const aiResponse = await apiService.generateTextStream(prompt, {
      maxTokens: null, // 移除token限制
      temperature: 0.8,
      type: 'outline'
    }, (chunk, fullContent) => {
      // 实时更新章节大纲
      chapterForm.value.description = fullContent
    })

    if (!aiResponse.trim()) {
      throw new Error('AI返回内容为空')
    }
    ElMessage.success('章节大纲生成成功')
  } catch (error) {
    console.error('AI生成大纲失败:', error)
    ElMessage.error(`大纲生成失败: ${error.message}`)
  } finally {
    isGeneratingOutline.value = false
  }
}

const generateFromOutline = () => {
  if (!currentChapter.value?.description) {
    ElMessage.warning('请先为章节添加大纲描述')
    return
  }
  // 打开AI正文生成弹窗，而不是直接调用生成函数
  openChapterGenerateDialog(currentChapter.value)
}

// 根据章节内容生成大纲
const generateOutlineFromContent = async (chapter) => {
  if (!checkApiAndBalance()) return

  if (!chapter.content || chapter.content.trim() === '') {
    ElMessage.warning('该章节暂无内容，无法生成大纲')
    return
  }

  // 清理HTML标签，获取纯文本内容
  const cleanContent = chapter.content.replace(/<[^>]*>/g, '').trim()
  
  if (cleanContent.length < 100) {
    ElMessage.warning('章节内容过短，建议先完善内容后再生成大纲')
    return
  }

  // 设置对话框数据并显示
  generatingOutlineChapter.value = chapter
  generatedOutlineContent.value = ''
  showOutlineGenerateDialog.value = true
  
  // 开始生成大纲
  generateOutlineWithDialog()
}

// 在对话框中生成大纲
const generateOutlineWithDialog = async () => {
  if (!generatingOutlineChapter.value) return
  
  isGeneratingOutlineDialog.value = true
  generatedOutlineContent.value = ''
  
  try {
    const chapter = generatingOutlineChapter.value
    const cleanContent = chapter.content.replace(/<[^>]*>/g, '').trim()

    const prompt = `=== 章节大纲总结任务 ===
请根据以下章节的具体内容，总结出简洁明了的章节大纲。

=== 章节信息 ===
章节标题：${chapter.title}
字数：${chapter.wordCount || cleanContent.length}字

=== 章节内容 ===
${cleanContent}

=== 生成要求 ===
1. 分析章节的主要情节线索和发展脉络
2. 提取关键的场景、人物互动和事件转折
3. 总结章节的核心冲突和解决方案
4. 概括章节在整体故事中的作用和意义
5. 大纲要简洁明了，突出重点，不超过300字

=== 输出格式 ===
请按以下结构输出：

【核心情节】
简述本章的主要情节发展

【关键场景】
列出重要的场景和转折点

【人物发展】
描述主要人物的行为和变化

【章节作用】
说明本章在整体故事中的意义

请生成章节大纲：`

    console.log('开始根据内容生成章节大纲:', chapter.title)

    console.log('开始根据内容生成章节大纲:', chapter.title)

    const aiResponse = await apiService.generateTextStream(prompt, {
      maxTokens: null,
      temperature: 0.7,
      type: 'outline'
    }, (chunk, fullContent) => {
      // 实时更新对话框中的内容
      generatedOutlineContent.value = fullContent
    })

    if (!aiResponse || !aiResponse.trim()) {
      throw new Error('AI返回空内容')
    }

    ElMessage.success('大纲生成完成！请预览后确认是否保存')
    console.log('章节大纲生成完成:', aiResponse.trim())

  } catch (error) {
    console.error('根据内容生成章节大纲失败:', error)
    
    let errorMessage = 'AI生成失败'
    if (error.message.includes('API请求失败') || error.message.includes('API Key')) {
      errorMessage = 'AI服务暂时不可用，请稍后重试'
    } else if (error.message.includes('网络')) {
      errorMessage = '网络连接失败，请检查网络后重试'
    } else if (error.message) {
      errorMessage = error.message
    }
    
    ElMessage.error(errorMessage)
  } finally {
    isGeneratingOutlineDialog.value = false
  }
}

// 确认保存生成的大纲
const confirmSaveOutline = async () => {
  if (!generatingOutlineChapter.value || !generatedOutlineContent.value.trim()) {
    ElMessage.warning('没有可保存的大纲内容')
    return
  }

  try {
    const chapter = generatingOutlineChapter.value
    const chapterData = {
      title: chapter.title,
      outline: generatedOutlineContent.value.trim(),
      content: chapter.content,
      status: chapter.status || 'draft',
      wordCount: chapter.wordCount || chapter.content.replace(/<[^>]*>/g, '').length
    }

    // 调用后端API更新章节
    const updatedChapter = await chapterApi.updateChapter(
      currentNovel.value.id,
      chapter.id,
      chapterData
    )

    // 更新本地章节数据
    if (chapters.value && Array.isArray(chapters.value) && isComponentMounted.value) {
      const index = chapters.value.findIndex(c => c && c.id === chapter.id)
      if (index > -1 && chapters.value[index]) {
        const updatedChapterData = {
          ...updatedChapter,
          description: updatedChapter.outline || updatedChapter.summary || '',
          createdAt: new Date(updatedChapter.createdAt),
          updatedAt: new Date(updatedChapter.updatedAt)
        }
        chapters.value.splice(index, 1, updatedChapterData)
        
        // 如果是当前章节，也更新当前章节数据
        if (currentChapter.value && currentChapter.value.id === chapter.id) {
          currentChapter.value = updatedChapterData
        }
      }
    }

    ElMessage.success(`《${chapter.title}》的大纲保存成功！`)
    showOutlineGenerateDialog.value = false
    resetOutlineDialog()

  } catch (error) {
    console.error('保存章节大纲失败:', error)
    ElMessage.error('保存失败: ' + (error.message || '未知错误'))
  }
}

// 重置大纲生成对话框
const resetOutlineDialog = () => {
  generatingOutlineChapter.value = null
  generatedOutlineContent.value = ''
  isGeneratingOutlineDialog.value = false
}

// 打开批量大纲生成对话框
const openBatchOutlineGenerateDialog = () => {
  if (!currentNovel.value) {
    ElMessage.warning('请先选择小说')
    return
  }

  if (chapters.value.length === 0) {
    ElMessage.warning('当前小说没有章节')
    return
  }

  // 重置状态
  resetBatchOutlineDialog()
  
  // 根据配置筛选可生成章节
  updateSelectedBatchChapters()
  
  showBatchOutlineDialog.value = true
}

// 更新批量选择的章节
const updateSelectedBatchChapters = () => {
  const filtered = chapters.value.filter(chapter => {
    // 检查是否有内容
    const hasContent = chapter.content && chapter.content.trim() !== ''
    
    // 检查是否有大纲
    const hasOutline = chapter.description && chapter.description.trim() !== ''
    
    // 应用筛选条件
    if (batchOutlineConfig.value.includeChaptersWithContent && hasContent) {
      if (!batchOutlineConfig.value.includeChaptersWithoutOutline) {
        // 只要有内容的章节，但要排除已有大纲的
        return !hasOutline
      } else if (!batchOutlineConfig.value.overwriteExistingOutline && hasOutline) {
        // 不覆盖已有大纲
        return false
      }
      return true
    }
    
    return false
  })
  
  selectedBatchChapters.value = filtered
}

// 开始批量生成大纲
const startBatchOutlineGenerate = async () => {
  if (!checkApiAndBalance()) return
  
  if (selectedBatchChapters.value.length === 0) {
    ElMessage.warning('没有符合条件的章节可以生成大纲')
    return
  }

  batchOutlineGenerating.value = true
  batchOutlineProgress.value = {
    current: 0,
    total: selectedBatchChapters.value.length,
    currentChapter: ''
  }
  batchOutlineResults.value = []

  try {
    for (let i = 0; i < selectedBatchChapters.value.length; i++) {
      const chapter = selectedBatchChapters.value[i]
      
      batchOutlineProgress.value.current = i + 1
      batchOutlineProgress.value.currentChapter = chapter.title

      try {
        // 生成单个章节的大纲
        const result = await generateSingleChapterOutline(chapter)
        
                 if (result.success) {
           batchOutlineResults.value.push({
             chapter: chapter.title,
             status: 'success',
             content: result.content,
             chapterId: chapter.id,
             selected: true,  // 默认选中待保存
             originalOutline: chapter.description || ''  // 保存原始大纲
           })
        } else {
                     batchOutlineResults.value.push({
             chapter: chapter.title,
             status: 'error',
             error: result.error,
             chapterId: chapter.id,
             selected: false
           })
        }
      } catch (error) {
                 batchOutlineResults.value.push({
           chapter: chapter.title,
           status: 'error',
           error: error.message || '生成失败',
           chapterId: chapter.id,
           selected: false
         })
      }

      // 添加延迟，避免请求过于频繁
      if (i < selectedBatchChapters.value.length - 1) {
        await new Promise(resolve => setTimeout(resolve, 1000))
      }
    }

         const successCount = batchOutlineResults.value.filter(r => r.status === 'success').length
     const errorCount = batchOutlineResults.value.filter(r => r.status === 'error').length
     
     ElMessage.success(`批量生成完成！成功: ${successCount}个，失败: ${errorCount}个。请确认后保存。`)
    
  } catch (error) {
    console.error('批量生成大纲失败:', error)
    ElMessage.error('批量生成过程中发生错误')
  } finally {
    batchOutlineGenerating.value = false
  }
}

// 生成单个章节的大纲（用于批量生成）
const generateSingleChapterOutline = async (chapter) => {
  try {
    const cleanContent = chapter.content.replace(/<[^>]*>/g, '').trim()
    
    if (cleanContent.length < 100) {
      return {
        success: false,
        error: '章节内容过短（少于100字）'
      }
    }

    const prompt = `=== 章节大纲总结任务 ===
请根据以下章节的具体内容，总结出简洁明了的章节大纲。

=== 章节信息 ===
章节标题：${chapter.title}
字数：${chapter.wordCount || cleanContent.length}字

=== 章节内容 ===
${cleanContent}

=== 生成要求 ===
1. 分析章节的主要情节线索和发展脉络
2. 提取关键的场景、人物互动和事件转折
3. 总结章节的核心冲突和解决方案
4. 概括章节在整体故事中的作用和意义
5. 大纲要简洁明了，突出重点，不超过300字

=== 输出格式 ===
请按以下结构输出：

【核心情节】
简述本章的主要情节发展

【关键场景】
列出重要的场景和转折点

【人物发展】
描述主要人物的行为和变化

【章节作用】
说明本章在整体故事中的意义

请生成章节大纲：`

    const aiResponse = await apiService.generateTextStream(prompt, {
      maxTokens: null,
      temperature: 0.7,
      type: 'outline'
    }, () => {
      // 批量生成时不需要实时更新UI
    })

    if (!aiResponse || !aiResponse.trim()) {
      return {
        success: false,
        error: 'AI返回空内容'
      }
    }

    return {
      success: true,
      content: aiResponse.trim()
    }

  } catch (error) {
    console.error(`生成章节"${chapter.title}"大纲失败:`, error)
    return {
      success: false,
      error: error.message || '未知错误'
    }
  }
}
// 批量保存选中的大纲
const saveBatchOutlines = async () => {
  const selectedResults = batchOutlineResults.value.filter(r => r.selected && r.status === 'success')
  
  if (selectedResults.length === 0) {
    ElMessage.warning('请至少选择一个大纲进行保存')
    return
  }

  batchSaving.value = true

  try {
    let savedCount = 0
    let errorCount = 0

    for (const result of selectedResults) {
      try {
        // 找到对应的章节
        const chapter = chapters.value.find(c => c.id === result.chapterId)
        if (!chapter) {
          errorCount++
          continue
        }

        // 更新后端数据
        const chapterData = {
          title: chapter.title,
          outline: result.content,
          content: chapter.content,
          status: chapter.status || 'draft',
          wordCount: chapter.wordCount || 0
        }

        await chapterApi.updateChapter(currentNovel.value.id, result.chapterId, chapterData)

        // 更新本地章节数据
        const index = chapters.value.findIndex(c => c.id === result.chapterId)
        if (index > -1) {
          chapters.value[index].description = result.content
        }

        // 如果是当前章节，也更新当前章节数据
        if (currentChapter.value && currentChapter.value.id === result.chapterId) {
          currentChapter.value.description = result.content
        }

        savedCount++
      } catch (error) {
        console.error(`保存章节 ${result.chapter} 的大纲失败:`, error)
        errorCount++
      }
    }

    if (errorCount === 0) {
      ElMessage.success(`成功保存 ${savedCount} 个章节的大纲`)
    } else {
      ElMessage.warning(`保存完成：成功 ${savedCount} 个，失败 ${errorCount} 个`)
    }

    // 保存完成后关闭对话框
    showBatchOutlineDialog.value = false

  } catch (error) {
    console.error('批量保存大纲失败:', error)
    ElMessage.error('保存过程中发生错误')
  } finally {
    batchSaving.value = false
  }
}

// 全选/取消全选
const toggleSelectAllOutlines = (selectAll) => {
  batchOutlineResults.value.forEach(result => {
    if (result.status === 'success') {
      result.selected = selectAll
    }
  })
}

// 重置批量大纲生成对话框
const resetBatchOutlineDialog = () => {
  batchOutlineGenerating.value = false
  batchSaving.value = false
  batchOutlineProgress.value = {
    current: 0,
    total: 0,
    currentChapter: ''
  }
  batchOutlineResults.value = []
  selectedBatchChapters.value = []
}

const enhanceContent = () => {
  if (!checkApiAndBalance()) return

  // 获取编辑器选中的内容
  let selectedText = ''

  if (editorRef.value) {
    try {
      const quill = editorRef.value.getQuill()
      if (quill) {
        const selection = quill.getSelection()
        if (selection && selection.length > 0) {
          selectedText = quill.getText(selection.index, selection.length)
        }
      }
    } catch (error) {
      console.warn('获取选择文本失败:', error)
      selectedText = ''
    }
  }

  // 设置优化内容
  if (selectedText.trim()) {
    // 有选择内容，优化选择的内容
    optimizeForm.value.originalContent = selectedText.trim()
    optimizeForm.value.mode = 'selection'
    ElMessage.info('检测到选择内容，将优化选择的文本')
  } else {
    // 没有选择内容，优化整篇文章
    const fullText = content.value.replace(/<[^>]*>/g, '').trim() // 去除HTML标签
    if (!fullText) {
      ElMessage.warning('当前章节没有内容可以优化')
      return
    }
    optimizeForm.value.originalContent = fullText
    optimizeForm.value.mode = 'full'
    ElMessage.info('未检测到选择内容，将优化整篇文章')
  }

  // 显示新的优化对话框
  showNewOptimizeDialog.value = true
}

// 新润色对话框相关方法
const canStartOptimize = computed(() => {
  return optimizeForm.value.originalContent.trim() &&
      (optimizeForm.value.selectedPrompt || optimizeForm.value.customPrompt.trim())
})

// 为新润色对话框选择提示词
const selectNewOptimizePrompt = (prompt) => {
  optimizeForm.value.selectedPrompt = prompt
  console.log('选择润色提示词:', prompt.title)
}

// 新续写对话框相关方法
const canStartContinue = computed(() => {
  return content.value.trim().length >= 50 // 至少需要50字的内容才能续写
})

// 打开续写对话框
const openContinueDialog = () => {
  if (!checkApiAndBalance()) return

  if (!currentChapter.value) {
    ElMessage.warning('请先选择一个章节')
    return
  }

  if (!content.value || content.value.trim().length < 50) {
    ElMessage.warning('请先写一些内容，AI将基于现有内容进行续写')
    return
  }

  // 重置表单
  continueForm.value.direction = ''
  continueForm.value.wordCount = 500
  continueStreamingContent.value = ''
  isContinueStreaming.value = false

  showNewContinueDialog.value = true
}

// 获取当前内容全文
const getCurrentFullContent = () => {
  if (!content.value) return ''

  // 移除HTML标签，返回纯文本内容
  return content.value.replace(/<[^>]*>/g, '').trim()
}

// 重置续写对话框
const resetContinueDialog = () => {
  continueForm.value.direction = ''
  continueForm.value.wordCount = 500
  continueStreamingContent.value = ''
  isContinueStreaming.value = false
}

// 开始新的续写
const startNewContinue = async () => {
  if (!canStartContinue.value) {
    ElMessage.warning('内容太少，无法进行续写')
    return
  }

  isContinueStreaming.value = true
  continueStreamingContent.value = ''

  try {
    const context = buildGenerationContext()
    const currentContent = content.value.replace(/<[^>]*>/g, '').trim()

    // 构建续写提示词
    let prompt = `=== 小说基本信息 ===
小说标题：${currentNovel.value?.title || '未命名小说'}
小说类型：${(() => {
      const genreMap = {
        'fantasy': '玄幻小说',
        'urban': '都市言情',
        'historical': '历史架空',
        'martial': '武侠修仙',
        'science': '科幻未来',
        'romance': '现代言情',
        'mystery': '悬疑推理',
        'adventure': '冒险奇幻',
        'horror': '恐怖惊悚',
        'general': '通用小说'
      }
      return genreMap[currentNovel.value?.genre] || '通用小说'
    })()}
小说简介：${currentNovel.value?.description || '暂无简介'}
=== 当前章节信息 ===
章节标题：${currentChapter.value.title}
章节大纲：${currentChapter.value.description || '暂无大纲'}
=== 续写任务 ===
请为上述小说的当前章节续写内容。

=== 已有内容（必须保持连贯） ===
${currentContent}

${context.characters.length > 0 ? `=== 主要人物设定 ===
${context.characters.map(char => `- ${char.name}：${char.personality || '暂无描述'}`).join('\n')}

` : ''}=== 续写要求 ===
1. 基于已有内容的风格和语调继续创作
2. 保持情节的连贯性和逻辑性
3. 符合章节大纲的发展方向
4. 续写长度约${continueForm.value.wordCount}字`

    // 如果有续写方向，添加到提示词中
    if (continueForm.value.direction.trim()) {
      prompt += `
5. 续写方向：${continueForm.value.direction.trim()}`
    }

    prompt += `
=== 核心约束（必须严格遵守） ===
1. 【连贯性】必须与已有内容在语言风格、情节发展、人物行为上完全连贯
2. 【一致性】人物性格、世界观设定、时间线必须与前文保持一致
3. 【逻辑性】情节发展必须符合逻辑，不能出现突兀的转折
4. 【主题控制】不得偏离章节大纲的主要情节线
请直接输出续写内容，无需额外说明：`

    console.log('开始新的AI续写:', prompt.substring(0, 200) + '...')

    // 流式调用AI续写
    const aiResponse = await apiService.generateTextStream(prompt, {
      maxTokens: null,
      temperature: 0.8,
      type: 'continue'
    }, (chunk, fullContent) => {
      // 实时更新流式内容
      continueStreamingContent.value = fullContent
    })

    if (!aiResponse.trim()) {
      throw new Error('AI返回内容为空')
    }

    // 设置最终续写结果
    continueStreamingContent.value = aiResponse.trim()
    ElMessage.success('续写完成')

  } catch (error) {
    console.error('AI续写失败:', error)
    ElMessage.error(`续写失败: ${error.message}`)
  } finally {
    isContinueStreaming.value = false
  }
}

// 停止续写流式输出
const stopContinueStreaming = () => {
  isContinueStreaming.value = false
  ElMessage.info('已停止续写')
}

// 复制续写内容
const copyContinueContent = async () => {
  if (!continueStreamingContent.value) {
    ElMessage.warning('没有可复制的内容')
    return
  }

  try {
    await navigator.clipboard.writeText(continueStreamingContent.value)
    ElMessage.success('续写内容已复制到剪贴板')
  } catch (error) {
    console.error('复制失败:', error)
    ElMessage.error('复制失败，请手动复制')
  }
}
// 追加续写内容到文章
const appendContinueContent = () => {
  if (!continueStreamingContent.value) {
    ElMessage.warning('没有可追加的内容')
    return
  }

  // 格式化续写内容
  const formattedContent = formatGeneratedContent(continueStreamingContent.value, '')

  // 追加到当前内容
  content.value = content.value + '\n' + formattedContent
  hasUnsavedChanges.value = true

  // 自动滚动编辑器到底部
  scrollEditorToBottom()

  ElMessage.success('续写内容已追加到文章')
  showNewContinueDialog.value = false

  // 自动保存
  setTimeout(() => {
    saveCurrentChapter()
  }, 1000)
}


const resetOptimizeDialog = () => {
  optimizeForm.value.optimizedContent = ''
  optimizeForm.value.customPrompt = ''
  optimizeForm.value.selectedPrompt = null
  optimizeStreamingContent.value = ''
  isOptimizeStreaming.value = false
}

const startNewOptimize = async () => {
  if (!canStartOptimize.value) {
    ElMessage.warning('请选择润色类型或输入自定义要求')
    return
  }

  isOptimizeStreaming.value = true
  optimizeStreamingContent.value = ''
  optimizeForm.value.optimizedContent = ''

  try {
    // 构建优化提示词
    let promptContent = ''
    if (optimizeForm.value.selectedPrompt) {
      promptContent = optimizeForm.value.selectedPrompt.content
    } else if (optimizeForm.value.customPrompt.trim()) {
      promptContent = optimizeForm.value.customPrompt.trim()
    }

    const fullPrompt = `${promptContent}

原始内容：
${optimizeForm.value.originalContent}

请直接输出优化后的内容，无需额外说明：`

    console.log('开始新的AI优化:', fullPrompt.substring(0, 200) + '...')

    // 流式调用AI优化
    const aiResponse = await apiService.generateTextStream(fullPrompt, {
      maxTokens: null,
      temperature: 0.7,
      type: 'optimize'
    }, (chunk, fullContent) => {
      // 实时更新流式内容
      optimizeStreamingContent.value = fullContent
    })

    if (!aiResponse.trim()) {
      throw new Error('AI返回内容为空')
    }

    // 设置最终优化结果
    optimizeForm.value.optimizedContent = aiResponse.trim()
    ElMessage.success('内容润色完成')

  } catch (error) {
    console.error('AI润色失败:', error)
    ElMessage.error(`润色失败: ${error.message}`)
  } finally {
    isOptimizeStreaming.value = false
    optimizeStreamingContent.value = ''
  }
}

const stopOptimizeStreaming = () => {
  isOptimizeStreaming.value = false
  optimizeStreamingContent.value = ''
  ElMessage.info('已停止润色')
}

const copyOptimizedContent = async () => {
  if (!optimizeForm.value.optimizedContent) {
    ElMessage.warning('没有可复制的内容')
    return
  }

  try {
    await navigator.clipboard.writeText(optimizeForm.value.optimizedContent)
    ElMessage.success('内容已复制到剪贴板')
  } catch (error) {
    console.error('复制失败:', error)
    ElMessage.error('复制失败，请手动复制')
  }
}

const replaceSelectedContent = () => {
  if (!optimizeForm.value.optimizedContent) {
    ElMessage.warning('没有可替换的内容')
    return
  }

  try {
    if (editorRef.value && optimizeForm.value.mode === 'selection') {
      // 检查是否有选择的内容
      const selectedText = editorRef.value.getSelectionText()
      if (selectedText) {
        // 替换选中的内容
        editorRef.value.insertText(optimizeForm.value.optimizedContent)
        ElMessage.success('选择内容已替换为润色结果')
        hasUnsavedChanges.value = true
        showNewOptimizeDialog.value = false

          // 自动保存
          setTimeout(() => {
            saveCurrentChapter()
          }, 1000)
      } else {
        ElMessage.warning('未找到选择的内容，请重新选择要替换的文本')
      }
    } else {
      ElMessage.warning('当前不是选择模式或编辑器未就绪')
    }
  } catch (error) {
    console.error('替换失败:', error)
    ElMessage.error('替换失败')
  }
}

const replaceFullContent = () => {
  if (!optimizeForm.value.optimizedContent) {
    ElMessage.warning('没有可替换的内容')
    return
  }

  ElMessageBox.confirm(
      '确定要用润色后的内容替换整篇文章吗？此操作不可撤销。',
      '确认替换',
      {
        confirmButtonText: '确定替换',
        cancelButtonText: '取消',
        type: 'warning'
      }
  ).then(() => {
    // 替换全文内容
    const formattedContent = formatGeneratedContent(optimizeForm.value.optimizedContent, currentChapter.value?.title || '')
    content.value = formattedContent
    hasUnsavedChanges.value = true

    ElMessage.success('全文内容已替换为润色结果')
    showNewOptimizeDialog.value = false

    // 自动保存
    setTimeout(() => {
      saveCurrentChapter()
    }, 1000)
  }).catch(() => {
    // 用户取消
  })
}

// 解析AI章节响应
const parseChapterResponse = (response) => {
  console.log('原始AI响应:', response)
  const chapters = []

  // 尝试多种解析策略
  const strategies = [
    // 策略1: 严格格式 "章节X："
    () => parseByChapterNumber(response),
    // 策略2: 按照标题和大纲字段分割
    () => parseByTitleAndOutline(response),
    // 策略3: 按照第X章格式分割
    () => parseByChapterFormat(response),
    // 策略4: 按照双换行分割成段落
    () => parseByParagraphs(response),
    // 策略5: 智能分割，寻找标题模式
    () => parseByTitlePattern(response)
  ]

  for (const strategy of strategies) {
    const result = strategy()
    if (result && result.length > 0) {
      console.log('解析成功，使用策略:', strategy.name, '，章节数:', result.length)
      result.forEach((ch, i) => console.log(`第${i+1}章: ${ch.title} - ${ch.description?.substring(0, 50)}...`))
      return result
    }
  }

  // 所有策略都失败，创建一个默认章节
  console.warn('所有解析策略都失败，创建默认章节')
  return [{
    title: 'AI生成章节',
    description: response.substring(0, 300) + (response.length > 300 ? '...' : '')
  }]
}

// 策略1: 按章节号分割
const parseByChapterNumber = (response) => {
  console.log('策略1: 按章节号分割')
  const chapters = []

  // 更灵活的章节分割正则，支持多种格式
  const chapterRegex = /章节(\d+)[：:\s]*[\r\n]/gi
  const matches = []
  let match

  while ((match = chapterRegex.exec(response)) !== null) {
    matches.push({
      index: match.index,
      number: parseInt(match[1]),
      fullMatch: match[0]
    })
  }

  console.log('找到章节标记:', matches.length, '个')

  if (matches.length === 0) {
    // 尝试更宽松的匹配
    const blocks = response.split(/章节\d+[：:]/i).filter(block => block.trim())
    console.log('宽松匹配找到块数:', blocks.length)

    if (blocks.length <= 1) return null

    blocks.forEach((block, index) => {
      if (index === 0 && !block.includes('标题')) return // 跳过第一个可能的空块

      const lines = block.split('\n').filter(line => line.trim())
      let title = `第${index}章`
      let description = ''

      for (const line of lines) {
        const trimmed = line.trim()
        if (trimmed.match(/^标题[：:]/)) {
          title = trimmed.replace(/^标题[：:]/, '').trim()
        } else if (trimmed.match(/^大纲[：:]/)) {
          description = trimmed.replace(/^大纲[：:]/, '').trim()
        } else if (description && !trimmed.match(/^(标题|大纲)/)) {
          description += '\n' + trimmed
        } else if (!description && !trimmed.match(/^(标题|大纲)/) && trimmed.length > 0) {
          description = trimmed
        }
      }

      if (title && description) {
        chapters.push({ title, description })
      }
    })
  } else {
    // 精确匹配处理
    for (let i = 0; i < matches.length; i++) {
      const currentMatch = matches[i]
      const nextMatch = matches[i + 1]

      const startIndex = currentMatch.index + currentMatch.fullMatch.length
      const endIndex = nextMatch ? nextMatch.index : response.length
      const block = response.substring(startIndex, endIndex).trim()

      console.log(`处理章节${currentMatch.number}:`, block.substring(0, 100))

      const lines = block.split('\n').filter(line => line.trim())
      let title = `第${currentMatch.number}章`
      let description = ''

      for (const line of lines) {
        const trimmed = line.trim()
        if (trimmed.match(/^标题[：:]/)) {
          title = trimmed.replace(/^标题[：:]/, '').trim()
        } else if (trimmed.match(/^大纲[：:]/)) {
          description = trimmed.replace(/^大纲[：:]/, '').trim()
        } else if (description && !trimmed.match(/^(标题|大纲)/)) {
          description += '\n' + trimmed
        } else if (!description && !trimmed.match(/^(标题|大纲)/) && trimmed.length > 0) {
          description = trimmed
        }
      }

      if (title && description) {
        chapters.push({ title, description })
        console.log(`成功解析章节${currentMatch.number}: ${title}`)
      }
    }
  }

  console.log('策略1解析结果:', chapters.length, '个章节')
  return chapters.length > 0 ? chapters : null
}

// 策略2: 按标题大纲字段分割
const parseByTitleAndOutline = (response) => {
  const chapters = []
  const lines = response.split('\n')
  let currentChapter = null

  for (const line of lines) {
    const trimmed = line.trim()

    if (trimmed.match(/^标题[：:]/)) {
      if (currentChapter && currentChapter.title && currentChapter.description) {
        chapters.push(currentChapter)
      }
      currentChapter = {
        title: trimmed.replace(/^标题[：:]/, '').trim(),
        description: ''
      }
    } else if (trimmed.match(/^大纲[：:]/)) {
      if (currentChapter) {
        currentChapter.description = trimmed.replace(/^大纲[：:]/, '').trim()
      }
    } else if (currentChapter && currentChapter.description && trimmed && !trimmed.match(/^(标题|大纲|章节)/)) {
      currentChapter.description += '\n' + trimmed
    }
  }

  if (currentChapter && currentChapter.title && currentChapter.description) {
    chapters.push(currentChapter)
  }

  return chapters.length > 0 ? chapters : null
}

// 策略3: 按第X章格式分割
const parseByChapterFormat = (response) => {
  const chapters = []
  const chapterRegex = /第\d+章[：:\s]*([^\n]+)/g
  let match
  const matches = []

  while ((match = chapterRegex.exec(response)) !== null) {
    matches.push({
      index: match.index,
      title: match[1].trim(),
      fullMatch: match[0]
    })
  }

  if (matches.length === 0) return null

  for (let i = 0; i < matches.length; i++) {
    const currentMatch = matches[i]
    const nextMatch = matches[i + 1]

    const startIndex = currentMatch.index + currentMatch.fullMatch.length
    const endIndex = nextMatch ? nextMatch.index : response.length
    const content = response.substring(startIndex, endIndex).trim()

    if (content) {
      chapters.push({
        title: currentMatch.title,
        description: content
      })
    }
  }

  return chapters.length > 0 ? chapters : null
}

// 策略4: 按段落分割
const parseByParagraphs = (response) => {
  const paragraphs = response.split(/\n\s*\n/).filter(p => p.trim())

  if (paragraphs.length < 2) return null

  const chapters = []

  for (const paragraph of paragraphs) {
    const lines = paragraph.split('\n').filter(l => l.trim())
    if (lines.length < 2) continue

    const title = lines[0].trim()
    const description = lines.slice(1).join('\n').trim()

    if (title && description && title.length < 100) {
      chapters.push({ title, description })
    }
  }

  return chapters.length > 0 ? chapters : null
}

// 策略5: 智能标题模式分割
const parseByTitlePattern = (response) => {
  const chapters = []
  const lines = response.split('\n').filter(line => line.trim())

  let currentTitle = ''
  let currentDescription = ''

  for (let i = 0; i < lines.length; i++) {
    const line = lines[i].trim()

    // 检测可能的标题行（较短且可能包含章节关键词）
    const isTitleLike = (
        line.length < 50 &&
        (line.includes('章') || line.includes('第') || line.match(/^\d+[\.\、]/)) &&
        !line.includes('：') && !line.includes(':')
    ) || (
        i === 0 || lines[i-1].trim() === ''
    ) && line.length < 30 && line.length > 3

    if (isTitleLike && currentDescription.length > 20) {
      // 保存前一个章节
      if (currentTitle && currentDescription) {
        chapters.push({
          title: currentTitle,
          description: currentDescription.trim()
        })
      }

      currentTitle = line
      currentDescription = ''
    } else {
      if (currentTitle) {
        currentDescription += (currentDescription ? '\n' : '') + line
      } else {
        currentTitle = line
      }
    }
  }

  // 添加最后一个章节
  if (currentTitle && currentDescription) {
    chapters.push({
      title: currentTitle,
      description: currentDescription.trim()
    })
  }

  return chapters.length > 0 ? chapters : null
}

// 获取模板描述
const getTemplateDescription = (template) => {
  const templates = {
    general: '通用章节模板，平衡叙述和对话',
    battle: '战斗场景模板，突出动作和紧张感',
    emotion: '情感戏模板，重点描写心理和情感',
    turning: '转折剧情模板，制造悬念和反转'
  }
  return templates[template] || '通用模板'
}
// 获取最近5章的详细信息
const getRecentChaptersDetail = () => {
  console.log('getRecentChaptersDetail 被调用，当前章节数量:', chapters.value.length)

  if (chapters.value.length === 0) {
    console.log('返回：暂无已有章节')
    return '暂无已有章节'
  }

  // 获取最近5章（或所有章节，如果不足5章）
  const recentCount = Math.min(5, chapters.value.length)
  const recentChapters = chapters.value.slice(-recentCount)

  console.log('最近章节数量:', recentCount, '章节详情:', recentChapters.map(ch => ({
    title: ch.title,
    description: ch.description,
    wordCount: ch.wordCount
  })))

  const result = recentChapters.map((ch, idx) => {
    const chapterIndex = chapters.value.length - recentCount + idx + 1
    let chapterInfo = `第${chapterIndex}章《${ch.title}》`

    if (ch.description && ch.description.trim()) {
      chapterInfo += `\n章节大纲：${ch.description}`
    } else {
      chapterInfo += `\n章节大纲：暂无大纲描述`
    }

    if (ch.wordCount && ch.wordCount > 0) {
      chapterInfo += `\n字数：${ch.wordCount}字`
    }

    return chapterInfo
  }).join('\n\n')

  console.log('最终返回的章节详情:', result)
  return result
}

// 获取视角描述
const getViewpointDescription = (style) => {
  const styles = {
    'first-person': '第一人称',
    'third-person': '第三人称',
    'omniscient': '全知视角'
  }
  return styles[style] || '第三人称'
}

// 获取正文生成类型描述
const getContentCategoryDescription = (category) => {
  const categories = {
    'content': '基础正文（标准章节内容生成）',
    'content-dialogue': '对话生成（以对话为主的内容）',
    'content-scene': '场景描写（环境氛围描写）',
    'content-action': '动作情节（动作和冲突为主）',
    'content-psychology': '心理描写（内心活动和情感）'
  }
  return categories[category] || '基础正文'
}

// 获取正文生成类型的具体指导
const getContentCategoryGuidance = (category) => {
  const guidance = {
    'content': '平衡叙述、对话、心理描写、环境描写，创造完整的章节内容',
    'content-dialogue': '重点突出人物对话，通过对话推进情节，展现人物性格和关系',
    'content-scene': '详细描写环境、氛围、场景细节，营造身临其境的感觉',
    'content-action': '重点描写动作场面、冲突情节，节奏紧凑，充满张力',
    'content-psychology': '深入刻画人物内心活动、情感变化、心理冲突'
  }
  return guidance[category] || '平衡各种描写手法，创造丰富的内容'
}

// 格式化生成的内容
const formatGeneratedContent = (rawContent, chapterTitle) => {
  // 清理内容
  let formatted = rawContent.trim()

  // 添加章节标题（如果没有的话）
  if (!formatted.includes(chapterTitle)) {
    formatted = `<h3>${chapterTitle}</h3>\n\n${formatted}`
  }

  // 段落格式化
  const paragraphs = formatted.split('\n').filter(p => p.trim())
  const htmlContent = paragraphs.map(paragraph => {
    const trimmed = paragraph.trim()

    // 处理标题
    if (trimmed.startsWith('#') || trimmed === chapterTitle) {
      return `<h3>${trimmed.replace(/^#+\s*/, '')}</h3>`
    }

    // 处理对话
    if (trimmed.startsWith('"') || trimmed.startsWith('"') || trimmed.startsWith('「')) {
      return `<p class="dialogue">${trimmed}</p>`
    }

    // 普通段落
    return `<p>${trimmed}</p>`
  }).join('')

  return htmlContent
}

// 构建生成上下文
const buildGenerationContext = () => {
  const currentIndex = chapters.value.findIndex(c => c.id === currentChapter.value?.id)
  const previousChapters = chapters.value.slice(0, currentIndex)

  return {
    characters: characters.value,
    worldSettings: worldSettings.value,
    corpus: corpusData.value,
    events: events.value,
    previousChapters: previousChapters,
    currentNovelInfo: currentNovel.value,
    // 新增：更详细的上下文信息
    totalChapters: chapters.value.length,
    currentChapterIndex: currentIndex + 1,
    storyProgress: currentIndex / Math.max(chapters.value.length - 1, 1), // 故事进度百分比
    recentEvents: events.value.filter(e => e.chapter && parseInt(e.chapter) <= currentIndex + 1).slice(-3), // 最近3个事件
    activeCharacters: characters.value.filter(char => char.role === 'protagonist' || char.role === 'antagonist'), // 主要角色
    storyTheme: currentNovel.value?.genre || '通用' // 故事主题
  }
}

// 世界观管理方法
const addWorldSetting = () => {
  worldForm.value = {
    title: '',
    description: '',
    category: 'setting',
    details: ''
  }
  showWorldDialog.value = true
}

const editWorldSetting = (setting) => {
  worldForm.value = { ...setting }
  showWorldDialog.value = true
}

const deleteWorldSetting = (setting) => {
  ElMessageBox.confirm(`确定要删除设定《${setting.title}》吗？`, '确认删除', {
    type: 'warning'
  }).then(async () => {
    if (!currentNovel.value?.id) {
      ElMessage.error('小说信息不存在')
      return
    }

    try {
      // 调用后端API删除世界观设定
      await worldSettingApi.deleteWorldSetting(currentNovel.value.id, setting.id)

      // 从store中移除
      novelStore.removeWorldSetting(setting.id)
      ElMessage.success('设定已删除')
    } catch (error) {
      console.error('删除世界观设定失败:', error)
      ElMessage.error('删除世界观设定失败: ' + (error.message || '未知错误'))
    }
  }).catch(() => {})
}

// 处理世界观设定操作
const handleWorldSettingAction = (command, setting) => {
  switch (command) {
    case 'edit':
      editWorldSetting(setting)
      break
    case 'duplicate':
      duplicateWorldSetting(setting)
      break
    case 'delete':
      deleteWorldSetting(setting)
      break
  }
}

// 复制世界观设定
const duplicateWorldSetting = (setting) => {
  const newSetting = {
    ...setting,
    id: new Date().getTime(),
    title: setting.title + ' (副本)',
    createdAt: new Date(),
    generated: false
  }
  novelStore.addWorldSetting(newSetting)
  ElMessage.success('设定已复制')
}



// 语料库管理方法
const addCorpus = () => {
  corpusForm.value = {
    id: null,
    title: '',
    type: 'description',
    content: '',
    tags: []
  }
  showCorpusDialog.value = true
}

const editCorpus = (corpus) => {
  corpusForm.value = { ...corpus }
  showCorpusDialog.value = true
}
const deleteCorpus = async (corpus) => {
  try {
    await ElMessageBox.confirm(
        `确定要删除语料"${corpus.title}"吗？`,
        '删除确认',
        {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }
    )

    if (!currentNovel.value?.id) {
      ElMessage.error('小说信息不存在')
      return
    }

    try {
      // 调用后端API删除语料
      await corpusApi.deleteCorpus(currentNovel.value.id, corpus.id)

      // 从本地语料列表中移除
      const index = corpusData.value.findIndex(item => item.id === corpus.id)
      if (index > -1) {
        corpusData.value.splice(index, 1)
        ElMessage.success('语料删除成功')
      }
    } catch (error) {
      console.error('删除语料失败:', error)
      ElMessage.error('删除语料失败: ' + (error.message || '未知错误'))
    }
  } catch {
    // 用户取消删除
  }
}

// 事件管理方法
const addEvent = () => {
  eventForm.value = {
    id: null,
    title: '',
    description: '',
    chapter: currentChapter.value?.title || '',
    time: new Date().toISOString().slice(0, 16),
    importance: 'normal'
  }
  showEventDialog.value = true
}

const editEvent = (event) => {
  eventForm.value = { ...event }
  showEventDialog.value = true
}

const saveEvent = async () => {
  if (!eventForm.value.title.trim()) {
    ElMessage.warning('请输入事件标题')
    return
  }

  if (!currentNovel.value?.id) {
    ElMessage.error('小说信息不存在')
    return
  }

  try {
    if (eventForm.value.id) {
      // 编辑现有事件
      const eventData = {
        title: eventForm.value.title,
        description: eventForm.value.description,
        chapter: eventForm.value.chapter,
        time: eventForm.value.time,
        importance: eventForm.value.importance
      }

      const updatedEvent = await eventApi.updateEvent(
          currentNovel.value.id,
          eventForm.value.id,
          eventData
      )

      // 更新本地数据
      const index = events.value.findIndex(e => e.id === eventForm.value.id)
      if (index > -1) {
        events.value[index] = {
          ...updatedEvent,
          createdAt: new Date(updatedEvent.createdAt),
          updatedAt: new Date(updatedEvent.updatedAt)
        }
      }
      ElMessage.success('事件信息已更新')
    } else {
      // 新增事件
      const eventData = {
        title: eventForm.value.title,
        description: eventForm.value.description,
        chapter: eventForm.value.chapter,
        time: eventForm.value.time,
        importance: eventForm.value.importance
      }

      const newEvent = await eventApi.createEvent(currentNovel.value.id, eventData)

      // 添加到本地事件列表
      events.value.push({
        ...newEvent,
        createdAt: new Date(newEvent.createdAt),
        updatedAt: new Date(newEvent.updatedAt)
      })

      ElMessage.success('事件创建成功')
    }
  } catch (error) {
    console.error('保存事件失败:', error)
    ElMessage.error('保存事件失败: ' + (error.message || '未知错误'))
    return
  }

  showEventDialog.value = false
}
const deleteEvent = (event) => {
  ElMessageBox.confirm(`确定要删除事件《${event.title}》吗？`, '确认删除', {
    type: 'warning'
  }).then(async () => {
    if (!currentNovel.value?.id) {
      ElMessage.error('小说信息不存在')
      return
    }

    try {
      // 调用后端API删除事件
      await eventApi.deleteEvent(currentNovel.value.id, event.id)

      // 从本地事件列表中移除
      const index = events.value.findIndex(e => e.id === event.id)
      if (index > -1) {
        events.value.splice(index, 1)
        ElMessage.success('事件已删除')
      }
    } catch (error) {
      console.error('删除事件失败:', error)
      ElMessage.error('删除事件失败: ' + (error.message || '未知错误'))
    }
  }).catch(() => {})
}

// 处理事件操作
const handleEventAction = (command, event) => {
  switch (command) {
    case 'edit':
      editEvent(event)
      break
    case 'delete':
      deleteEvent(event)
      break
  }
}

// 更新章节状态
const updateChapterStatus = () => {
  if (!currentChapter.value) return

  // 同步更新章节列表中的状态和其他数据
  const chapterIndex = chapters.value.findIndex(ch => ch.id === currentChapter.value.id)
  if (chapterIndex > -1) {
    chapters.value[chapterIndex].status = currentChapter.value.status
    chapters.value[chapterIndex].title = currentChapter.value.title
    chapters.value[chapterIndex].description = currentChapter.value.description // 前端的outline数据
    chapters.value[chapterIndex].content = currentChapter.value.content || content.value
    chapters.value[chapterIndex].wordCount = currentChapter.value.wordCount || contentWordCount.value
    chapters.value[chapterIndex].updatedAt = new Date()
  }

  // 保存更新
  saveCurrentChapter()

  ElMessage.success(`章节状态已更新为：${getChapterStatusText(currentChapter.value.status)}`)
}

// 世界观保存方法
const saveWorldSetting = async () => {
  if (!worldForm.value.title.trim()) {
    ElMessage.warning('请输入设定标题')
    return
  }

  if (!currentNovel.value?.id) {
    ElMessage.error('小说信息不存在')
    return
  }

  try {
    if (worldForm.value.id) {
      // 编辑现有设定
      const worldSettingData = {
        title: worldForm.value.title,
        description: worldForm.value.description,
        category: worldForm.value.category,
        details: worldForm.value.details
      }

      const updatedWorldSetting = await worldSettingApi.updateWorldSetting(
          currentNovel.value.id,
          worldForm.value.id,
          worldSettingData
      )

      // 更新store中的数据
      novelStore.updateWorldSetting(worldForm.value.id, {
        ...updatedWorldSetting,
        createdAt: new Date(updatedWorldSetting.createdAt),
        updatedAt: new Date(updatedWorldSetting.updatedAt)
      })
      ElMessage.success('设定信息已更新')
    } else {
      // 新增设定
      const worldSettingData = {
        title: worldForm.value.title,
        description: worldForm.value.description,
        category: worldForm.value.category,
        details: worldForm.value.details
      }

      const newWorldSetting = await worldSettingApi.createWorldSetting(currentNovel.value.id, worldSettingData)

      // 添加到store中
      novelStore.addWorldSetting({
        ...newWorldSetting,
        createdAt: new Date(newWorldSetting.createdAt),
        updatedAt: new Date(newWorldSetting.updatedAt)
      })

      ElMessage.success('设定创建成功')
    }
  } catch (error) {
    console.error('保存世界观设定失败:', error)
    ElMessage.error('保存世界观设定失败: ' + (error.message || '未知错误'))
    return
  }

  showWorldDialog.value = false
}
// 语料库保存方法
const saveCorpus = async () => {
  if (!corpusForm.value.title.trim()) {
    ElMessage.warning('请输入语料标题')
    return
  }

  if (!currentNovel.value?.id) {
    ElMessage.error('小说信息不存在')
    return
  }

  try {
    if (corpusForm.value.id) {
      // 编辑现有语料
      const corpusDataToUpdate = {
        title: corpusForm.value.title,
        type: corpusForm.value.type,
        content: corpusForm.value.content,
        tags: corpusForm.value.tags || []
      }

      const updatedCorpus = await corpusApi.updateCorpus(
          currentNovel.value.id,
          corpusForm.value.id,
          corpusDataToUpdate
      )

      // 更新本地数据
      const index = corpusData.value.findIndex(c => c.id === corpusForm.value.id)
      if (index > -1) {
        corpusData.value[index] = {
          ...updatedCorpus,
          createdAt: new Date(updatedCorpus.createdAt),
          updatedAt: new Date(updatedCorpus.updatedAt)
        }
      }
      ElMessage.success('语料信息已更新')
    } else {
      // 新增语料
      const corpusDataToSave = {
        title: corpusForm.value.title,
        type: corpusForm.value.type,
        content: corpusForm.value.content,
        tags: corpusForm.value.tags || []
      }

      const newCorpus = await corpusApi.createCorpus(currentNovel.value.id, corpusDataToSave)

      // 添加到本地语料列表
      corpusData.value.push({
        ...newCorpus,
        createdAt: new Date(newCorpus.createdAt),
        updatedAt: new Date(newCorpus.updatedAt)
      })

      ElMessage.success('语料创建成功')
    }
  } catch (error) {
    console.error('保存语料失败:', error)
    ElMessage.error('保存语料失败: ' + (error.message || '未知错误'))
    return
  }

  showCorpusDialog.value = false
}

// 自动保存防抖定时器
let autoSaveTimer = null

const onContentChange = () => {
  // 检查组件是否还在正常状态
  if (!currentChapter.value || !currentNovel.value) {
    return
  }

  // 清除之前的定时器
  if (autoSaveTimer) {
    clearTimeout(autoSaveTimer)
  }

  // 设置新的定时器，2秒后自动保存
  autoSaveTimer = setTimeout(() => {
    // 再次检查组件状态
    if (currentChapter.value && currentNovel.value) {
      autoSave()
    }
  }, 2000)
}

// 自动保存函数
const autoSave = async () => {
  // 多重检查确保组件状态正常
  if (!currentChapter.value || !currentNovel.value || !chapters.value) {
    return
  }

  try {
    isSaving.value = true

    // 使用异步方式进行保存，并处理可能的错误
    await new Promise((resolve) => {
      setTimeout(async () => {
        try {
          // 再次检查组件状态
          if (currentChapter.value && currentNovel.value) {
            await saveCurrentChapter()
          }
        } catch (error) {
          console.error('自动保存失败:', error)
        } finally {
          // 只有在组件状态正常时才更新 isSaving
          if (typeof isSaving.value !== 'undefined') {
            isSaving.value = false
          }
          resolve()
        }
      }, 300) // 短暂延迟以显示保存状态
    })
  } catch (error) {
    console.error('自动保存过程出错:', error)
    // 确保 isSaving 状态被重置
    if (typeof isSaving.value !== 'undefined') {
      isSaving.value = false
    }
  }
}
// 初始化
const initNovel = async () => {
  const novelIdParam = route.query.novelId
  if (novelIdParam) {
    try {
      // pageLoading.value = true
      // 使用简单的数字ID
      const novelId = parseInt(novelIdParam)
      console.log('正在加载小说ID:', novelId)

      // 从后端API加载小说数据
      const novel = await novelApi.getNovel(novelId)

      if (novel) {
        currentNovel.value = novel

        // 检查是否需要跳转到特定章节
        const chapterIdParam = route.query.chapterId
        if (chapterIdParam) {
          // 如果指定了章节ID，先查找章节所在页面
          console.log('检测到章节ID参数，查找章节所在页面:', chapterIdParam)
          await loadChapterPage(novelId, parseInt(chapterIdParam))
        } else {
          // 没有指定章节，使用分页加载
        await loadChaptersWithPagination(novelId)
        }

        try {
          worldSettingsLoading.value = true
          // 从后端API加载世界观设定数据
          const worldSettingsResponse = await worldSettingApi.getWorldSettings(novelId)

          // 清空并重新加载世界观设定到store中
          novelStore.worldSettings.splice(0, novelStore.worldSettings.length)
          if (worldSettingsResponse && worldSettingsResponse.length > 0) {
            worldSettingsResponse.forEach(setting => {
              novelStore.worldSettings.push({
                ...setting,
                createdAt: setting.createdAt ? new Date(setting.createdAt) : new Date(),
                updatedAt: setting.updatedAt ? new Date(setting.updatedAt) : new Date()
              })
            })
          }

          console.log('从后端加载世界观设定数据:', novelStore.worldSettings.length, '个设定')
        } catch (error) {
          console.error('加载世界观设定数据失败:', error)
          // 如果后端加载失败，尝试从localStorage加载作为备用
          const localData = JSON.parse(localStorage.getItem('novels') || '[]')
          const localNovel = localData.find(n => n.id === novelId)

          novelStore.worldSettings.splice(0, novelStore.worldSettings.length)
          if (localNovel?.worldSettings && localNovel.worldSettings.length > 0) {
            localNovel.worldSettings.forEach(setting => {
              novelStore.worldSettings.push(setting)
            })
          }
          ElMessage.warning('世界观设定数据加载失败，使用本地缓存数据')
        } finally {
          worldSettingsLoading.value = false
        }

        try {
          corpusLoading.value = true
          // 从后端API加载语料库数据
          const response = await corpusApi.getCorpusList(novelId)
          console.log('语料库数据响应:', response)

          // 处理后端响应数据结构
          let corpusDataArray = []
          if (response && response.data) {
            // 如果是标准的 Result 格式 {code, message, data}
            if (Array.isArray(response.data)) {
              corpusDataArray = response.data
            } else {
              console.warn('response.data 不是数组格式:', response.data)
              corpusDataArray = []
            }
          } else if (response && Array.isArray(response)) {
            // 直接数组格式
            corpusDataArray = response
          } else {
            console.warn('未知的响应数据格式:', response)
            corpusDataArray = []
          }

          corpusData.value = corpusDataArray.map(corpus => ({
            ...corpus,
            createdAt: corpus.createdAt ? new Date(corpus.createdAt) : new Date(),
            updatedAt: corpus.updatedAt ? new Date(corpus.updatedAt) : new Date()
          }))

          console.log('从后端加载语料库数据:', corpusData.value.length, '个语料')
        } catch (error) {
          console.error('加载语料库数据失败:', error)
          // 如果后端加载失败，尝试从localStorage加载作为备用
          const localData = JSON.parse(localStorage.getItem('novels') || '[]')
          const localNovel = localData.find(n => n.id === novelId)
          corpusData.value = localNovel?.corpusData || []
          ElMessage.warning('语料库数据加载失败，使用本地缓存数据')
        } finally {
          corpusLoading.value = false
        }

        try {
          eventsLoading.value = true
          // 从后端API加载事件数据
          const response = await eventApi.getEventsList(novelId)
          console.log('事件数据响应:', response)

          // 处理后端响应数据结构
          let eventsData = []
          if (response && response.data) {
            // 如果是标准的 Result 格式 {code, message, data}
            if (Array.isArray(response.data)) {
              eventsData = response.data
            } else {
              console.warn('response.data 不是数组格式:', response.data)
              eventsData = []
            }
          } else if (response && Array.isArray(response)) {
            // 直接数组格式
            eventsData = response
          } else {
            console.warn('未知的响应数据格式:', response)
            eventsData = []
          }

          events.value = eventsData.map(event => ({
            ...event,
            createdAt: event.createdAt ? new Date(event.createdAt) : new Date(),
            updatedAt: event.updatedAt ? new Date(event.updatedAt) : new Date()
          }))

          console.log('从后端加载事件数据:', events.value.length, '个事件')
        } catch (error) {
          console.error('加载事件数据失败:', error)
          // 如果后端加载失败，尝试从localStorage加载作为备用
          const localData = JSON.parse(localStorage.getItem('novels') || '[]')
          const localNovel = localData.find(n => n.id === novelId)
          events.value = localNovel?.events || []
          ElMessage.warning('事件数据加载失败，使用本地缓存数据')
        } finally {
          eventsLoading.value = false
        }

        // 如果存在章节，选择合适的章节
        if (chapters.value.length > 0) {
          // 检查URL参数中是否指定了特定章节
          const chapterIdParam = route.query.chapterId
          if (chapterIdParam) {
            const targetChapterId = parseInt(chapterIdParam)
            const targetChapter = chapters.value.find(ch => ch.id === targetChapterId)
            if (targetChapter) {
              console.log('选择指定章节:', targetChapter.title)
              selectChapter(targetChapter)
            } else {
              console.warn('当前页面未找到指定章节ID:', targetChapterId, '，使用第一章节')
          selectChapter(chapters.value[0])
            }
          } else {
            // 没有指定章节，选择第一章节
            selectChapter(chapters.value[0])
          }
        }

      } else {
        ElMessage.error('小说不存在')
        router.push('/novels')
      }
    } catch (error) {
      console.error('加载小说失败:', error)
      ElMessage.error('加载小说失败')
      router.push('/novels')
    } finally {
      pageLoading.value = false
    }
  } else {
    ElMessage.error('缺少小说ID参数')
    router.push('/novels')
    pageLoading.value = false
  }
}
// 生命周期
onMounted(async () => {
  await initNovel()
  await loadPrompts()
})

onUnmounted(() => {
  try {
    // 设置组件已卸载标志
    isComponentMounted.value = false
    
    // 清理自动保存定时器
    if (autoSaveTimer) {
      clearTimeout(autoSaveTimer)
      autoSaveTimer = null
    }

    // 页面卸载时自动保存（同步方式，避免异步问题）
    if (currentChapter.value && currentNovel.value) {
      try {
        // 同步保存当前章节内容到本地
        const chapterData = {
          ...currentChapter.value,
          content: content.value,
          wordCount: content.value.replace(/<[^>]*>/g, '').length,
          updatedAt: new Date()
        }
        
        // 保存到localStorage
        const localData = JSON.parse(localStorage.getItem('novels') || '[]')
        const novelIndex = localData.findIndex(n => n.id === currentNovel.value.id)
        if (novelIndex > -1) {
          const chapterIndex = localData[novelIndex].chapterList?.findIndex(c => c.id === currentChapter.value.id)
          if (chapterIndex > -1) {
            localData[novelIndex].chapterList[chapterIndex] = chapterData
            localStorage.setItem('novels', JSON.stringify(localData))
          }
        }
      } catch (error) {
        console.error('卸载时保存失败:', error)
      }
    }

    // Quill 编辑器会自动清理，无需手动销毁
    editorRef.value = null
  } catch (error) {
    console.error('组件卸载清理失败:', error)
  }
})

// 监听路由参数变化
watch(() => route.query.novelId, () => {
  if (route.query.novelId) {
    // 重置当前章节
    currentChapter.value = null
    content.value = ''
    initNovel()
  }
})

// 批量生成角色提示词相关函数
const openBatchCharacterPromptSelector = () => {
  selectedPromptCategory.value = 'character'
  showPromptDialog.value = true
  selectedPrompt.value = null
  promptVariables.value = {}
  finalPrompt.value = ''
}

const clearBatchCharacterPrompt = () => {
  batchCharacterSelectedPrompt.value = null
  batchCharacterPromptVariables.value = {}
  batchCharacterFinalPrompt.value = ''
}

const generateBatchCharacterFinalPrompt = () => {
  if (!batchCharacterSelectedPrompt.value) {
    batchCharacterFinalPrompt.value = ''
    return
  }

  let result = batchCharacterSelectedPrompt.value.content
  Object.keys(batchCharacterPromptVariables.value).forEach(variable => {
    const value = batchCharacterPromptVariables.value[variable] || `{${variable}}`
    result = result.replace(new RegExp(`\\{${variable}\\}`, 'g'), value)
  })

  batchCharacterFinalPrompt.value = result
}

// 世界观生成提示词相关函数
const openWorldSettingPromptSelector = () => {
  selectedPromptCategory.value = 'worldview'
  showPromptDialog.value = true
  selectedPrompt.value = null
  promptVariables.value = {}
  finalPrompt.value = ''
}

const clearWorldSettingPrompt = () => {
  worldSettingSelectedPrompt.value = null
  worldSettingPromptVariables.value = {}
  worldSettingFinalPrompt.value = ''
}

const autoFillWorldSettingVariables = () => {
  if (!worldSettingSelectedPrompt.value) return

  // 自动填充基本信息
  worldSettingPromptVariables.value['小说标题'] = currentNovel.value?.title || '未命名小说'
  worldSettingPromptVariables.value['小说类型'] = getChineseGenre(currentNovel.value?.genre)
  worldSettingPromptVariables.value['小说简介'] = currentNovel.value?.description || '暂无简介'
  worldSettingPromptVariables.value['生成数量'] = worldGenerateConfig.value.count.toString()

  // 设定类型要求
  const settingTypes = []
  if (worldGenerateConfig.value.includeGeography) settingTypes.push('地理环境')
  if (worldGenerateConfig.value.includeCulture) settingTypes.push('文化社会')
  if (worldGenerateConfig.value.includeHistory) settingTypes.push('历史背景')
  if (worldGenerateConfig.value.includeMagic) settingTypes.push('魔法体系')
  if (worldGenerateConfig.value.includeTechnology) settingTypes.push('科技水平')
  if (worldGenerateConfig.value.includePolitics) settingTypes.push('政治势力')
  if (worldGenerateConfig.value.includeReligion) settingTypes.push('宗教信仰')
  if (worldGenerateConfig.value.includeEconomy) settingTypes.push('经济贸易')
  if (worldGenerateConfig.value.includeRaces) settingTypes.push('种族设定')
  if (worldGenerateConfig.value.includeLanguage) settingTypes.push('语言文字')
  worldSettingPromptVariables.value['设定类型'] = settingTypes.join('、')

  // 特殊要求
  worldSettingPromptVariables.value['特殊要求'] = worldGenerateConfig.value.customPrompt || '符合小说世界观设定'

  generateWorldSettingFinalPrompt()
}

const generateWorldSettingFinalPrompt = () => {
  if (!worldSettingSelectedPrompt.value) {
    worldSettingFinalPrompt.value = ''
    return
  }

  let result = worldSettingSelectedPrompt.value.content
  Object.keys(worldSettingPromptVariables.value).forEach(variable => {
    const value = worldSettingPromptVariables.value[variable] || `{${variable}}`
    result = result.replace(new RegExp(`\\{${variable}\\}`, 'g'), value)
  })

  worldSettingFinalPrompt.value = result
}

// 章节生成弹窗相关方法
const clearAllMaterials = () => {
  selectedMaterials.value = {
    characters: [],
    worldSettings: [],
    corpus: [],
    events: [],
    chapters: []
  }

  // 清空前文概要章节选择
  selectedContextChapters.value = []
  if (promptVariables.value['前文概要']) {
    promptVariables.value['前文概要'] = ''
    generateFinalPrompt()
  }

  ElMessage.success('已清空所有选择')
}

const selectAllMaterials = (type) => {
  switch (type) {
    case 'characters':
      selectedMaterials.value.characters = [...characters.value]
      break
    case 'worldSettings':
      selectedMaterials.value.worldSettings = [...worldSettings.value]
      break
    case 'corpus':
      selectedMaterials.value.corpus = [...corpusData.value]
      break
    case 'events':
      selectedMaterials.value.events = [...events.value]
      break
    case 'chapters':
      // 章节选择已改为使用上下文选择，这里保持原有逻辑但不再使用
      selectedMaterials.value.chapters = [...availableChaptersForSelection.value]
      break
  }
  const typeText = type === 'characters' ? '人物' :
      type === 'worldSettings' ? '世界观' :
          type === 'corpus' ? '语料' :
              type === 'events' ? '事件线' :
                  type === 'chapters' ? '章节' : '素材'
  ElMessage.success(`已选择所有${typeText}`)
}

const useDefaultPrompt = () => {
  selectedPrompt.value = null
  promptVariables.value = {}
  finalPrompt.value = ''
  ElMessage.info('已切换到默认提示词')
}

const refreshPrompts = async () => {
  // 刷新提示词列表
  try {
    await loadPrompts()
    ElMessage.success('提示词列表已刷新')
  } catch (error) {
    ElMessage.error('刷新提示词列表失败')
  }
}

const createPromptForCategory = () => {
  router.push('/prompts-library')
}

const copyPrompt = () => {
  if (finalPrompt.value) {
    navigator.clipboard.writeText(finalPrompt.value)
    ElMessage.success('提示词已复制到剪贴板')
  }
}

const editPrompt = () => {
  ElMessage.info('您可以直接在预览框中编辑提示词')
}



// 新增AI功能弹窗方法
const openAISingleChapterDialog = () => {
  aiSingleChapterForm.value = {
    title: '',
    plotRequirement: '',
    template: 'general'
  }
  showAISingleChapterDialog.value = true
}
const openAIBatchChapterDialog = () => {
  aiBatchChapterForm.value = {
    count: 3,
    plotRequirement: '',
    template: 'general'
  }
  showAIBatchChapterDialog.value = true
}
const resetAISingleChapterDialog = () => {
  aiSingleChapterForm.value = {
    title: '',
    plotRequirement: '',
    template: 'general'
  }
  // 重置自定义提示词
  singleChapterSelectedPrompt.value = null
  singleChapterPromptVariables.value = {}
  singleChapterFinalPrompt.value = ''
  streamingContent.value = ''
  isStreaming.value = false
}

const resetAIBatchChapterDialog = () => {
  aiBatchChapterForm.value = {
    count: 3,
    plotRequirement: '',
    template: 'general'
  }
  // 重置自定义提示词
  batchChapterSelectedPrompt.value = null
  batchChapterPromptVariables.value = {}
  batchChapterFinalPrompt.value = ''
  activePromptCollapse.value = ['promptContent']
  streamingContent.value = ''
  isStreaming.value = false
}

const generateSingleChapter = async () => {
  if (!checkApiAndBalance()) return

  if (!aiSingleChapterForm.value.title.trim()) {
    ElMessage.warning('请输入章节标题')
    return
  }

  isGeneratingChapters.value = true
  isStreaming.value = true
  streamingType.value = 'single-chapter'
  streamingContent.value = ''

  try {
    // 检查是否有选中的自定义提示词
    if (singleChapterSelectedPrompt.value && singleChapterFinalPrompt.value) {
      console.log('使用自定义提示词生成单章')
      await generateSingleChapterWithPrompt(singleChapterFinalPrompt.value)
      return
    }

    // 使用默认模板，确保包含用户填写的所有信息
    const prompt = `=== 小说基本信息 ===
小说标题：${currentNovel.value?.title || '未命名小说'}
小说类型：${getChineseGenre(currentNovel.value?.genre)}
小说简介：${currentNovel.value?.description || '暂无简介'}

=== 单章生成任务 ===
【重要提醒】：请只生成一个章节的大纲，不要生成多个章节！

目标章节信息：
- 章节标题：${aiSingleChapterForm.value.title}
- 情节要求：${aiSingleChapterForm.value.plotRequirement || '请根据章节标题合理发展'}
- 模板类型：${getTemplateDescription(aiSingleChapterForm.value.template)}
- 章节序号：第${chapters.value.length + 1}章

已有章节概况：
${chapters.value.map((ch, idx) => `第${idx + 1}章：${ch.title} - ${ch.description || '暂无描述'}`).join('\n')}

【核心要求】：
1. 只生成一个章节（第${chapters.value.length + 1}章）的详细大纲
2. 使用用户指定的章节标题：${aiSingleChapterForm.value.title}
3. 严格遵循用户的情节要求：${aiSingleChapterForm.value.plotRequirement || '按章节标题合理发展'}
4. 与前文保持逻辑连贯性，推进主线剧情发展
5. 包含具体的情节要点、人物发展、重要事件等
6. 不要生成多个章节，只生成一个章节的内容
请严格按照以下格式返回（只返回一个章节）：
大纲：[详细的章节内容描述，包含主要情节、人物发展、重要事件等]`

    console.log('开始AI生成单章大纲:', prompt)

    const aiResponse = await apiService.generateTextStream(prompt, {
      maxTokens: null,
      temperature: 0.8,
      type: 'outline'
    }, (chunk, fullContent) => {
      streamingContent.value = fullContent
    })

    if (!aiResponse.trim()) {
      throw new Error('AI返回内容为空')
    }

    // 保存章节到后端
    try {
      const chapterToSave = {
        title: aiSingleChapterForm.value.title,
        outline: aiResponse.replace(/^大纲：/, '').trim(), // 前端的description对应后端的outline
        content: '',
        wordCount: 0,
        status: 'draft'
      }

      const savedChapter = await chapterApi.createChapter(currentNovel.value.id, chapterToSave)

      // 添加到本地章节列表
      const newChapter = {
        ...savedChapter,
        description: savedChapter.outline || savedChapter.summary || '', // 后端的outline映射到前端的description
        createdAt: new Date(savedChapter.createdAt),
        updatedAt: new Date(savedChapter.updatedAt)
      }

      chapters.value.push(newChapter)
      showAISingleChapterDialog.value = false
      ElMessage.success('单章大纲生成并保存成功')
    } catch (saveError) {
      console.error('保存章节失败:', saveError)
      ElMessage.error('保存章节失败: ' + saveError.message)
    }
  } catch (error) {
    console.error('AI生成单章失败:', error)
    ElMessage.error(`单章生成失败: ${error.message}`)
  } finally {
    isGeneratingChapters.value = false
    isStreaming.value = false
    streamingContent.value = ''
  }
}

const generateBatchChapters = async () => {
  if (!checkApiAndBalance()) return

  console.log('开始批量生成章节')
  console.log('当前章节列表:', chapters.value.map(ch => ({ title: ch.title, description: ch.description })))

  // 检查是否有选中的自定义提示词
  if (batchChapterSelectedPrompt.value && batchChapterFinalPrompt.value) {
    console.log('使用自定义提示词生成')
    // 使用自定义提示词生成
    await generateBatchChaptersWithPrompt(batchChapterFinalPrompt.value)
    return
  }

  console.log('使用默认模板生成')

  isGeneratingChapters.value = true
  isStreaming.value = true
  streamingType.value = 'batch-chapters'
  streamingContent.value = ''

  try {
    const count = aiBatchChapterForm.value.count
    const plotRequirement = aiBatchChapterForm.value.plotRequirement
    const template = aiBatchChapterForm.value.template

    console.log('批量生成章节配置检查:', {
      count: count,
      plotRequirement: plotRequirement,
      template: template,
      formData: aiBatchChapterForm.value
    })

    // 构建章节编号示例
    const chapterExamples = []
    for (let i = 1; i <= count; i++) {
      chapterExamples.push(`章节${i}：
标题：[章节标题]
大纲：[详细的章节内容描述，包含主要情节、人物发展、重要事件等]`)
    }

    const prompt = `=== 小说基本信息 ===
小说标题：${currentNovel.value?.title || '未命名小说'}
小说类型：${getChineseGenre(currentNovel.value?.genre)}
小说简介：${currentNovel.value?.description || '暂无简介'}

=== 章节生成任务 ===
请为上述小说生成${count}个章节大纲。

【用户具体要求】：
- 生成章节数量：${count}个章节（不多不少）
- 用户情节要求：${plotRequirement || '请根据小说主题合理发展'}
- 模板类型：${getTemplateDescription(template)}
- 每个章节包含：标题、详细大纲描述
- 章节之间要有逻辑连贯性
- 严格遵循用户的情节要求，围绕用户指定的情节发展
已有章节：${chapters.value.length}个
=== 前文章节信息（重要参考） ===
${getRecentChaptersDetail()}

请严格按照以下格式返回${count}个章节：

${chapterExamples.join('\n\n')}
【重要约束】：
1. 必须严格按照"章节X："格式开始每个章节（X为数字1到${count}）
2. 每个章节必须包含"标题："和"大纲："两个字段
3. 必须生成完整的${count}个章节，缺一不可
4. 确保格式完全一致，便于程序解析
5. 不要生成超过${count}个章节
6. 不要生成少于${count}个章节

请现在开始生成${count}个章节大纲：`

    console.log('批量生成章节最终提示词:', prompt)
    console.log('请求生成章节数量:', count)
    console.log('前5章详细信息:', getRecentChaptersDetail())

    const aiResponse = await apiService.generateTextStream(prompt, {
      maxTokens: null, // 移除token限制
      temperature: 0.8,
      type: 'outline'
    }, (chunk, fullContent) => {
      streamingContent.value = fullContent
    })

    if (!aiResponse.trim()) {
      throw new Error('AI返回内容为空')
    }

    // 解析AI响应，提取章节信息
    console.log('AI响应长度:', aiResponse.length)
    console.log('AI响应内容:', aiResponse)

    const newChapters = parseChapterResponse(aiResponse)

    console.log('解析结果:', newChapters)
    console.log('期望生成数量:', count, '实际解析数量:', newChapters.length)

    if (newChapters.length !== count) {
      console.warn(`警告：期望生成${count}个章节，但实际解析出${newChapters.length}个章节`)
      ElMessage.warning(`期望生成${count}个章节，但实际解析出${newChapters.length}个章节`)
    }

    // 保存章节到后端并添加到本地列表
    const savedChapters = []
    for (let index = 0; index < newChapters.length; index++) {
      const chapterData = newChapters[index]
      try {
        const chapterToSave = {
          title: chapterData.title || `AI生成章节 ${chapters.value.length + index + 1}`,
          outline: chapterData.description || chapterData.outline || '暂无描述', // 前端的description对应后端的outline
          content: '',
          wordCount: 0,
          status: 'draft'
        }

        console.log(`正在保存章节 ${index + 1}:`, chapterToSave.title)
        const savedChapter = await chapterApi.createChapter(currentNovel.value.id, chapterToSave)

        // 添加到本地章节列表
        const newChapter = {
          ...savedChapter,
          description: savedChapter.outline || savedChapter.summary || '', // 后端的outline映射到前端的description
          createdAt: new Date(savedChapter.createdAt),
          updatedAt: new Date(savedChapter.updatedAt)
        }

        chapters.value.push(newChapter)
        savedChapters.push(newChapter)
        console.log(`成功保存章节 ${index + 1}:`, newChapter.title)
      } catch (error) {
        console.error(`保存章节 ${index + 1} 失败:`, error)
        ElMessage.error(`保存章节"${chapterData.title}"失败: ${error.message}`)
      }
    }

    showAIBatchChapterDialog.value = false
    if (savedChapters.length > 0) {
      ElMessage.success(`成功生成并保存${savedChapters.length}个章节大纲`)
    }
  } catch (error) {
    console.error('AI批量生成章节失败:', error)
    ElMessage.error(`批量生成失败: ${error.message}`)
  } finally {
    isGeneratingChapters.value = false
    isStreaming.value = false
    streamingContent.value = ''
  }
}

const selectPromptForSingleChapter = () => {
  selectedPromptCategory.value = 'outline'
  showPromptDialog.value = true
}

// 使用自定义提示词生成单章
const generateSingleChapterWithPrompt = async (customPrompt) => {
  if (!checkApiAndBalance()) return

  isGeneratingChapters.value = true
  isStreaming.value = true
  streamingType.value = 'single-chapter'
  streamingContent.value = ''

  try {
    // 在自定义提示词中确保包含用户填写的基本信息
    const promptWithUserInput = `=== 用户输入信息 ===
章节标题：${aiSingleChapterForm.value.title}
情节要求：${aiSingleChapterForm.value.plotRequirement || '请根据章节标题合理发展'}
模板类型：${getTemplateDescription(aiSingleChapterForm.value.template)}

=== 小说基本信息 ===
小说标题：${currentNovel.value?.title || '未命名小说'}
小说类型：${getChineseGenre(currentNovel.value?.genre)}
小说简介：${currentNovel.value?.description || '暂无简介'}

=== 已有章节概况 ===
${chapters.value.map((ch, idx) => `第${idx + 1}章：${ch.title} - ${ch.description || '暂无描述'}`).join('\n')}

=== 基于以上信息，请按照以下要求生成章节 ===
${customPrompt}

=== 重要约束 ===
【关键】：请只生成一个章节的大纲，不要生成多个章节！
1. 只生成一个章节（第${chapters.value.length + 1}章）的详细大纲
2. 必须使用用户指定的章节标题：${aiSingleChapterForm.value.title}
3. 必须遵循用户的情节要求：${aiSingleChapterForm.value.plotRequirement || '按章节标题合理发展'}
4. 与已有章节保持逻辑连贯性，推进主线剧情发展
5. 包含具体的情节要点、人物发展、重要事件等
6. 不要生成多个章节，无论提示词中是否提到"10章"等内容，都只生成一个章节
请严格按照以下格式返回（只返回一个章节）：
大纲：[详细的章节内容描述，包含主要情节、人物发展、重要事件等]`

    console.log('使用自定义提示词生成单章:', promptWithUserInput.substring(0, 300) + '...')

    const aiResponse = await apiService.generateTextStream(promptWithUserInput, {
      maxTokens: null,
      temperature: 0.8,
      type: 'outline'
    }, (chunk, fullContent) => {
      streamingContent.value = fullContent
    })

    if (!aiResponse.trim()) {
      throw new Error('AI返回内容为空')
    }

    // 保存章节到后端
    try {
      const chapterToSave = {
        title: aiSingleChapterForm.value.title,
        outline: aiResponse.replace(/^大纲：/, '').trim(), // 前端的description对应后端的outline
        content: '',
        wordCount: 0,
        status: 'draft'
      }

      const savedChapter = await chapterApi.createChapter(currentNovel.value.id, chapterToSave)

      // 添加到本地章节列表
      const newChapter = {
        ...savedChapter,
        description: savedChapter.outline || savedChapter.summary || '', // 后端的outline映射到前端的description
        createdAt: new Date(savedChapter.createdAt),
        updatedAt: new Date(savedChapter.updatedAt)
      }

      chapters.value.push(newChapter)
      showAISingleChapterDialog.value = false
      ElMessage.success('使用自定义提示词生成单章并保存成功')
    } catch (saveError) {
      console.error('保存章节失败:', saveError)
      ElMessage.error('保存章节失败: ' + saveError.message)
    }
  } catch (error) {
    console.error('使用自定义提示词生成单章失败:', error)
    ElMessage.error(`单章生成失败: ${error.message}`)
  } finally {
    isGeneratingChapters.value = false
    isStreaming.value = false
    streamingContent.value = ''
  }
}

const selectPromptForBatchChapter = () => {
  console.log('打开批量章节提示词选择对话框')
  console.log('当前章节数量:', chapters.value.length)
  console.log('当前章节列表:', chapters.value.map(ch => ({ title: ch.title, description: ch.description })))

  selectedPromptCategory.value = 'outline'
  showPromptDialog.value = true

  // 自动填充批量章节生成的变量
  nextTick(() => {
    if (selectedPrompt.value) {
      console.log('nextTick中调用autoFillBatchChapterVariables')
      autoFillBatchChapterVariables()
    }
  })
}

// 自动填充批量章节变量
const autoFillBatchChapterVariables = () => {
  if (!selectedPrompt.value) {
    console.log('autoFillBatchChapterVariables: 没有选中的提示词')
    return
  }

  console.log('开始自动填充批量章节变量')

  // 自动填充基本信息
  promptVariables.value['小说标题'] = currentNovel.value?.title || '未命名小说'
  promptVariables.value['小说类型'] = getChineseGenre(currentNovel.value?.genre)
  promptVariables.value['小说简介'] = currentNovel.value?.description || '暂无简介'
  promptVariables.value['生成章节数量'] = aiBatchChapterForm.value.count.toString()
  promptVariables.value['情节要求'] = aiBatchChapterForm.value.plotRequirement || '请根据小说主题合理发展'
  promptVariables.value['模板类型'] = getTemplateDescription(aiBatchChapterForm.value.template)

  // 填充已有章节信息（使用详细的前5章信息）
  const chaptersDetail = getRecentChaptersDetail()
  promptVariables.value['已有章节'] = chaptersDetail

  console.log('批量章节变量填充完成:', {
    小说标题: promptVariables.value['小说标题'],
    已有章节: chaptersDetail.substring(0, 200) + '...',
    变量数量: Object.keys(promptVariables.value).length
  })

  generateFinalPrompt()
}

// 自动填充单章变量
const autoFillSingleChapterVariables = () => {
  if (!selectedPrompt.value) {
    console.log('autoFillSingleChapterVariables: 没有选中的提示词')
    return
  }

  console.log('开始自动填充单章变量')

  // 自动填充基本信息
  promptVariables.value['小说标题'] = currentNovel.value?.title || '未命名小说'
  promptVariables.value['小说类型'] = getChineseGenre(currentNovel.value?.genre)
  promptVariables.value['小说简介'] = currentNovel.value?.description || '暂无简介'
  promptVariables.value['章节标题'] = aiSingleChapterForm.value.title || ''
  promptVariables.value['情节要求'] = aiSingleChapterForm.value.plotRequirement || '请根据章节标题合理发展'
  promptVariables.value['模板类型'] = getTemplateDescription(aiSingleChapterForm.value.template)

  // 填充已有章节信息
  const chaptersDetail = getRecentChaptersDetail()
  promptVariables.value['已有章节'] = chaptersDetail

  console.log('单章变量填充完成:', {
    小说标题: promptVariables.value['小说标题'],
    章节标题: promptVariables.value['章节标题'],
    情节要求: promptVariables.value['情节要求'],
    变量数量: Object.keys(promptVariables.value).length
  })

  generateFinalPrompt()
}

// 监听批量章节表单变化，自动更新提示词变量
watch(() => aiBatchChapterForm.value, () => {
  if (showAIBatchChapterDialog.value && selectedPrompt.value && selectedPromptCategory.value === 'outline') {
    console.log('批量章节表单变化，重新填充提示词变量')
    autoFillBatchChapterVariables()
  }
}, { deep: true })

// 监听单章表单变化，自动更新提示词变量
watch(() => aiSingleChapterForm.value, () => {
  if (showAISingleChapterDialog.value && selectedPrompt.value && selectedPromptCategory.value === 'outline') {
    console.log('单章表单变化，重新填充提示词变量')
    autoFillSingleChapterVariables()
  }
}, { deep: true })

// 使用自定义提示词批量生成章节
const generateBatchChaptersWithPrompt = async (customPrompt) => {
  if (!checkApiAndBalance()) return

  isGeneratingChapters.value = true
  isStreaming.value = true
  streamingType.value = 'batch-chapters'
  streamingContent.value = ''

  try {
    const count = aiBatchChapterForm.value.count
    const plotRequirement = aiBatchChapterForm.value.plotRequirement
    const template = aiBatchChapterForm.value.template

    console.log('使用自定义提示词批量生成章节配置检查:', {
      count: count,
      plotRequirement: plotRequirement,
      template: template,
      customPrompt: customPrompt.substring(0, 200) + '...'
    })

    console.log('使用自定义提示词:', {
      原始提示词长度: customPrompt.length,
      是否包含已有章节: customPrompt.includes('已有章节'),
      前5章详细信息: getRecentChaptersDetail().substring(0, 300) + '...'
    })

    // 获取前5章详细信息
    const recentChaptersDetail = getRecentChaptersDetail()

    // 在自定义提示词前面添加用户输入和前文信息
    const promptWithChapters = `=== 用户输入信息 ===
生成数量：${count}个章节
用户情节要求：${plotRequirement || '请根据小说主题合理发展'}
模板类型：${getTemplateDescription(template)}

=== 小说基本信息 ===
小说标题：${currentNovel.value?.title || '未命名小说'}
小说类型：${getChineseGenre(currentNovel.value?.genre)}
小说简介：${currentNovel.value?.description || '暂无简介'}

=== 前文章节信息（重要参考） ===
${recentChaptersDetail}

=== 基于以上信息，请按照以下要求生成新章节 ===
${customPrompt}`

    console.log('添加前5章信息后的提示词长度:', promptWithChapters.length)
    console.log('确认包含章节信息:', promptWithChapters.includes('第') && promptWithChapters.includes('章'))

    // 在自定义提示词基础上添加格式约束
    const promptWithFormat = `${promptWithChapters}

=== 重要格式约束（必须严格遵守） ===
无论上述提示词如何，你必须严格按照以下格式输出${count}个章节，不得有任何偏差：

章节1：
标题：[章节标题]
大纲：[详细的章节内容描述，包含主要情节、人物发展、重要事件等]

章节2：
标题：[章节标题]
大纲：[详细的章节内容描述，包含主要情节、人物发展、重要事件等]

章节3：
标题：[章节标题]
大纲：[详细的章节内容描述，包含主要情节、人物发展、重要事件等]

【核心约束】：
1. 必须严格按照"章节X："格式开始每个章节（X为数字1到${count}）
2. 每个章节必须包含"标题："和"大纲："两个字段
3. 必须生成完整的${count}个章节，缺一不可
4. 确保格式完全一致，便于程序解析
5. 不要生成超过${count}个章节
6. 不要生成少于${count}个章节
7. 标题要简洁有吸引力
8. 大纲要详细具体，包含具体的情节发展
9. 严格遵循用户的情节要求：${plotRequirement || '请根据小说主题合理发展'}
请现在开始生成${count}个章节大纲：`

    console.log('使用自定义提示词批量生成 - 最终提示词:')
    console.log('==================== 完整提示词开始 ====================')
    console.log(promptWithFormat)
    console.log('==================== 完整提示词结束 ====================')
    console.log('请求生成章节数量:', count)
    console.log('前5章详细信息:', getRecentChaptersDetail())

    const aiResponse = await apiService.generateTextStream(promptWithFormat, {
      maxTokens: null, // 移除token限制
      temperature: 0.8,
      type: 'outline'
    }, (chunk, fullContent) => {
      streamingContent.value = fullContent
    })

    if (!aiResponse.trim()) {
      throw new Error('AI返回内容为空')
    }

    // 解析AI响应，提取章节信息
    console.log('AI响应长度:', aiResponse.length)
    console.log('AI响应内容:', aiResponse)

    const newChapters = parseChapterResponse(aiResponse)

    console.log('解析结果:', newChapters)
    console.log('期望生成数量:', count, '实际解析数量:', newChapters.length)

    if (newChapters.length !== count) {
      console.warn(`警告：期望生成${count}个章节，但实际解析出${newChapters.length}个章节`)
      ElMessage.warning(`期望生成${count}个章节，但实际解析出${newChapters.length}个章节`)
    }

    // 保存章节到后端并添加到本地列表
    const savedChapters = []
    for (let index = 0; index < newChapters.length; index++) {
      const chapterData = newChapters[index]
      try {
        const chapterToSave = {
          title: chapterData.title || `AI生成章节 ${chapters.value.length + index + 1}`,
          outline: chapterData.description || chapterData.outline || '暂无描述', // 前端的description对应后端的outline
          content: '',
          wordCount: 0,
          status: 'draft'
        }

        console.log(`正在保存章节 ${index + 1}:`, chapterToSave.title)
        const savedChapter = await chapterApi.createChapter(currentNovel.value.id, chapterToSave)

        // 添加到本地章节列表
        const newChapter = {
          ...savedChapter,
          description: savedChapter.outline || savedChapter.summary || '', // 后端的outline映射到前端的description
          createdAt: new Date(savedChapter.createdAt),
          updatedAt: new Date(savedChapter.updatedAt)
        }

        chapters.value.push(newChapter)
        savedChapters.push(newChapter)
        console.log(`成功保存章节 ${index + 1}:`, newChapter.title)
      } catch (error) {
        console.error(`保存章节 ${index + 1} 失败:`, error)
        ElMessage.error(`保存章节"${chapterData.title}"失败: ${error.message}`)
      }
    }

    showAIBatchChapterDialog.value = false
    if (savedChapters.length > 0) {
      ElMessage.success(`成功使用自定义提示词生成并保存${savedChapters.length}个章节大纲`)
    }
  } catch (error) {
    console.error('AI批量生成章节失败:', error)
    ElMessage.error(`批量生成失败: ${error.message}`)
  } finally {
    isGeneratingChapters.value = false
    isStreaming.value = false
    streamingContent.value = ''
  }
}
</script>

<style scoped>
.writer-container {
  height: 85vh;
  display: flex;
  flex-direction: column;
  background-color: #f5f7fa;
}

.title-bar {
  height: 50px;
  background: white;
  border-bottom: 1px solid #e4e7ed;
  display: flex;
  align-items: center;
  padding: 0 10px;
  flex-shrink: 0;
}

.title-left {
  display: flex;
  align-items: center;
  gap: 15px;
}

.novel-title {
  font-size: 16px;
  font-weight: 600;
  
}



.main-content {
  flex: 1;
  display: flex;
  gap: 16px;
  padding: 16px;
  overflow: hidden;
}

/* 右侧纵向标签栏 */
.right-tabs-panel {
  width: 70px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  background: #f8f9fa;
  border-left: 1px solid #e4e7ed;
}

.vertical-tabs {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 50px 0;
}

.vertical-tab-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 16px 8px;
  cursor: pointer;
  transition: all 0.2s ease;
  background: transparent;
  position: relative;
  min-height: 80px;
  justify-content: center;
}

.vertical-tab-item::before {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 0;
  background: #409eff;
  transition: height 0.2s ease;
}

.vertical-tab-item:hover {
  background: rgba(64, 158, 255, 0.08);
}

.vertical-tab-item:hover::before {
  height: 30px;
}

.vertical-tab-item.active {
  background: rgba(64, 158, 255, 0.12);
  color: #409eff;
}

.vertical-tab-item.active::before {
  height: 40px;
}

.vertical-tab-item .tab-icon {
  font-size: 22px;
  margin-bottom: 6px;
  line-height: 1;
  transition: transform 0.2s ease;
}

.vertical-tab-item:hover .tab-icon {
  transform: scale(1.1);
}

.vertical-tab-item .tab-label {
  font-size: 11px;
  font-weight: 500;
  text-align: center;
  line-height: 1.2;
  white-space: nowrap;
  opacity: 0.8;
}

.vertical-tab-item.active .tab-label {
  opacity: 1;
  font-weight: 600;
}

.left-panel {
  width: 280px;
  flex-shrink: 0;
  background: #f8f9fa;
  border-right: 1px solid #e4e7ed;
  display: flex;
  flex-direction: column;
}


.empty-state p {
  margin-bottom: 16px;
}

.editor-panel {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  background: white;
}

.editor-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: 16px;
  overflow: hidden;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-weight: 600;
}
/* 新的编辑器头部样式 */
.editor-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  padding-bottom: 16px;
  margin-bottom: 16px;
  border-bottom: 1px solid #e4e7ed;
  background: white;
}
.editor-header-left {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.chapter-title {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
  
  line-height: 1.4;
}

.chapter-meta {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 13px;
  color: #909399;
}

.word-count {
  font-weight: 500;
  color: #606266;
}

.editor-header-right {
  flex-shrink: 0;
  margin-left: 20px;
}

.saving-indicator {
  color: #409eff !important;
  animation: pulse 1.5s infinite;
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.6; }
}

/* 编辑器内容样式优化 - 更适合小说阅读 */
.editor-wrapper :deep(.w-e-text-container) {
  background-color: #fcfcfc;
  border: none;
}

.editor-wrapper :deep(.w-e-text) {
  font-family: 'Microsoft YaHei', 'PingFang SC', 'Hiragino Sans GB', 'Source Han Sans CN', 'WenQuanYi Micro Hei', sans-serif;
  font-size: 16px;
  line-height: 2.0;
  color: #2c3e50;
  padding: 30px 40px;
  letter-spacing: 0.5px;
  text-align: justify;
}

.editor-wrapper :deep(.w-e-text p) {
  margin: 0 0 1.2em 0;
  text-indent: 2em;
  line-height: 2.0;
}

.editor-wrapper :deep(.w-e-text h1),
.editor-wrapper :deep(.w-e-text h2),
.editor-wrapper :deep(.w-e-text h3) {
  margin: 1.5em 0 1em 0;
  line-height: 1.6;
  text-indent: 0;
}

.editor-wrapper :deep(.w-e-text h1) {
  font-size: 24px;
  font-weight: 600;
}
.editor-wrapper :deep(.w-e-text h2) {
  font-size: 20px;
  font-weight: 600;
}

.editor-wrapper :deep(.w-e-text h3) {
  font-size: 18px;
  font-weight: 600;
}



.editor-container {
  flex: 1;
  border: 1px solid #e4e7ed;
  border-radius: 8px;
  overflow: hidden;
  background: white;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.editor-wrapper {
  height: 100%;
  display: flex;
  flex-direction: column;
}


.preview-content {
  line-height: 1.8;
  
}



/* 现代化弹窗样式 */
.chapter-generate-content {
  padding: 0;
}

.generate-config-section {
  margin-bottom: 16px;
}

.config-card-modern {
  border: 1px solid #e4e7ed;
  border-radius: 8px;
  overflow: hidden;
}

.config-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.config-left {
  display: flex;
  align-items: center;
  gap: 12px;
}

.config-title {
  font-weight: 600;
  
}

.config-item {
  margin-bottom: 0;
}

.config-item .el-form-item__label {
  font-size: 12px;
  color: #606266;
  font-weight: 500;
}


.section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
}

.section-title {
  font-size: 16px;
  font-weight: 600;
  
  margin: 0;
}

.materials-tabs {
  border: 1px solid #e4e7ed;
  border-radius: 8px;
  overflow: hidden;
}

.materials-tabs .el-tabs__header {
  margin: 0;
  background-color: #f8f9fa;
}
.materials-tabs .el-tabs__nav-wrap::after {
  display: none;
}
.tab-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  background-color: #fafbfc;
  border-bottom: 1px solid #e4e7ed;
  min-height: 48px;
  flex-wrap: nowrap;
}

.tab-count {
  font-size: 12px;
  color: #606266;
}

.materials-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 12px;
  padding: 16px;
  max-height: 300px;
  overflow-y: auto;
}

.material-card {
  border: 2px solid #e4e7ed;
  border-radius: 6px;
  padding: 12px;
  cursor: pointer;
  transition: all 0.2s;
  background-color: #ffffff;
  position: relative;
}

.material-card:hover {
  border-color: #409eff;
  background-color: #f0f9ff;
  transform: translateY(-1px);
  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.1);
}

.material-card.selected {
  border-color: #409eff;
  background-color: #ecf5ff;
  box-shadow: 0 0 0 1px #409eff;
}

.material-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 8px;
}

.material-name {
  font-size: 14px;
  font-weight: 600;
  
  line-height: 1.2;
}

.material-desc {
  font-size: 12px;
  color: #606266;
  line-height: 1.4;
  margin: 0 0 8px 0;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.material-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.empty-materials {
  text-align: center;
  padding: 40px 20px;
  color: #909399;
}

.category-selection-modern {
  margin-bottom: 16px;
}

.category-header {
  font-size: 14px;
  font-weight: 600;
  
  margin-bottom: 12px;
}

.category-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 8px;
}
.category-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 12px 8px;
  border: 2px solid #e4e7ed;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.2s;
  background-color: #ffffff;
}

.category-card:hover {
  border-color: #409eff;
  background-color: #f0f9ff;
}

.category-card.active {
  border-color: #409eff;
  background-color: #ecf5ff;
  color: #409eff;
}
.category-icon {
  font-size: 20px;
  margin-bottom: 4px;
}
.category-name {
  font-size: 12px;
  font-weight: 500;
  text-align: center;
}

.prompt-selection-modern {
  border: 1px solid #e4e7ed;
  border-radius: 8px;
  overflow: hidden;
}

.prompt-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  background-color: #f8f9fa;
  border-bottom: 1px solid #e4e7ed;
  font-size: 14px;
  font-weight: 500;
  
}

.prompt-list-modern {
  max-height: 250px;
  overflow-y: auto;
  padding: 8px;
}

.prompt-item-modern {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px;
  border: 1px solid #e4e7ed;
  border-radius: 6px;
  margin-bottom: 8px;
  cursor: pointer;
  transition: all 0.2s;
  background-color: #ffffff;
}

.prompt-item-modern:hover {
  border-color: #409eff;
  background-color: #f0f9ff;
}

.prompt-item-modern.active {
  border-color: #409eff;
  background-color: #ecf5ff;
}

.prompt-content {
  flex: 1;
}

.prompt-title {
  font-size: 14px;
  font-weight: 600;
  
  margin: 0 0 4px 0;
}

.prompt-desc {
  font-size: 12px;
  color: #606266;
  margin: 0 0 8px 0;
  line-height: 1.4;
}

.prompt-meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
}



.prompt-actions {
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.empty-prompts {
  text-align: center;
  padding: 40px 20px;
  color: #909399;
}

.variables-section {
  margin-top: 16px;
  border: 1px solid #e4e7ed;
  border-radius: 8px;
  overflow: hidden;
}

.variables-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  background-color: #f8f9fa;
  border-bottom: 1px solid #e4e7ed;
  font-size: 14px;
  font-weight: 500;
  
}

.variables-form {
  padding: 16px;
}

.variable-item {
  margin-bottom: 16px;
}

.variable-label {
  display: block;
  font-size: 12px;
  color: #606266;
  font-weight: 500;
  margin-bottom: 4px;
}

.preview-section {
  margin-top: 16px;
  border: 1px solid #e4e7ed;
  border-radius: 8px;
  overflow: hidden;
}

.preview-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  background-color: #f8f9fa;
  border-bottom: 1px solid #e4e7ed;
  font-size: 14px;
  font-weight: 500;
  
}

.preview-actions {
  display: flex;
  gap: 8px;
}

.preview-content {
  padding: 16px;
}

.preview-textarea {
  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
  font-size: 12px;
  line-height: 1.5;
}


.action-buttons {
  display: flex;
  gap: 12px;
}



.form-item-with-ai {
  display: flex;
  align-items: center;
}

.form-item-with-ai .el-input {
  flex: 1;
}

.form-item-with-ai .el-button {
  margin-top: 8px;
}

/* 章节简介区域样式 */
.chapter-description-wrapper {
  position: relative;
  width: 100%;
}

.chapter-description-wrapper .description-textarea {
  width: 100%;
}

.chapter-description-wrapper .description-textarea :deep(.el-textarea__inner) {
  min-height: 140px !important;
  font-size: 14px;
  line-height: 1.8;
  padding: 12px 95px 12px 12px !important; /* 右侧留出95px空间给按钮 */
  resize: vertical;
}

.chapter-description-wrapper .ai-generate-btn {
  position: absolute;
  top: 10px;
  right: 10px;
  padding: 5px 10px;
  font-size: 12px;
  height: 28px;
  min-width: 75px;
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  box-shadow: 0 2px 4px rgba(64, 158, 255, 0.1);
  transition: all 0.3s ease;
  z-index: 1;
}

.chapter-description-wrapper .ai-generate-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(64, 158, 255, 0.2);
}

.chapter-description-wrapper .ai-generate-btn .el-icon {
  font-size: 13px;
}

.chapter-description-wrapper .ai-generate-btn span {
  font-size: 12px;
  font-weight: 500;
}
.dialogue {
  font-style: italic;
  color: #2c3e50;
  padding-left: 16px;
  border-left: 3px solid #409eff;
  margin: 8px 0;
}





.chapter-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 4px;
}















/* 章节状态下拉菜单样式 */
.chapter-status-dropdown .el-select-dropdown__item {
  padding: 6px 16px;
  font-size: 12px;
}

.chapter-status-dropdown .el-select-dropdown__item.selected {
  font-weight: 600;
}

/* 章节元信息样式优化 */
.chapter-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.chapter-meta .el-select {
  min-width: 70px;
}

.chapter-meta .el-select .el-input__wrapper {
  padding: 0 8px;
  height: 24px;
  font-size: 12px;
}

/* 新的AI优化对话框样式 */
.new-optimize-container {
  max-height: 70vh;
  overflow-y: auto;
}

.optimize-config-card,
.optimize-result-card {
  height: 600px;
  display: flex;
  flex-direction: column;
}

.optimize-config-card .el-card__body,
.optimize-result-card .el-card__body {
  flex: 1;
  overflow-y: auto;
}

.prompt-selection {
  margin-bottom: 20px;
}

.prompt-selection h4 {
  margin: 0 0 12px 0;
  
  font-size: 14px;
  font-weight: 600;
}

.prompt-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.prompt-item {
  padding: 12px;
  border: 1px solid #e4e7ed;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.3s;
}

.prompt-item:hover {
  border-color: #409eff;
  background-color: #f0f9ff;
}

.prompt-item.active {
  border-color: #409eff;
  background-color: #ecf5ff;
  box-shadow: 0 0 0 1px #409eff;
}

.prompt-title {
  font-size: 13px;
  font-weight: 600;
  
  margin-bottom: 4px;
}

.prompt-desc {
  font-size: 11px;
  color: #606266;
  line-height: 1.4;
}

.custom-prompt {
  margin-bottom: 20px;
}

.custom-prompt h4 {
  margin: 0 0 12px 0;
  
  font-size: 14px;
  font-weight: 600;
}

.original-content-preview {
  margin-bottom: 20px;
}

.original-content-preview h4 {
  margin: 0 0 12px 0;
  
  font-size: 14px;
  font-weight: 600;
}

.content-preview {
  padding: 12px;
  background-color: #f8f9fa;
  border-radius: 6px;
  font-size: 12px;
  color: #606266;
  line-height: 1.5;
  max-height: 120px;
  overflow-y: auto;
  word-wrap: break-word;
}

.content-stats {
  margin-top: 8px;
  font-size: 11px;
  color: #909399;
}

.streaming-area {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.streaming-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
  padding-bottom: 8px;
  border-bottom: 1px solid #e4e7ed;
}

.streaming-status {
  color: #409eff;
  font-size: 14px;
  font-weight: 500;
}

.streaming-content-box {
  flex: 1;
  background-color: #f8f9fa;
  border-radius: 6px;
  padding: 16px;
  overflow-y: auto;
  min-height: 300px;
}

.streaming-text {
  font-size: 14px;
  line-height: 1.8;
  
  white-space: pre-wrap;
  word-wrap: break-word;
}

.result-area {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.result-content {
  flex: 1;
  background-color: #ffffff;
  border: 1px solid #e4e7ed;
  border-radius: 6px;
  padding: 16px;
  font-size: 14px;
  line-height: 1.8;
  
  overflow-y: auto;
  white-space: pre-wrap;
  word-wrap: break-word;
  min-height: 300px;
}

.result-stats {
  margin-top: 12px;
  display: flex;
  justify-content: space-between;
  font-size: 12px;
  color: #909399;
}

.empty-result {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.dialog-footer {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}

.dialog-footer:has(.action-info) {
  justify-content: space-between;
  align-items: center;
  padding: 16px 0 0 0;
  border-top: 1px solid #e4e7ed;
}
.dialog-footer .action-info {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: #606266;
}

.dialog-footer .action-buttons {
  display: flex;
  gap: 12px;
}

/* 流式生成内容样式 */
.streaming-content-area {
  margin-bottom: 16px;
}

.streaming-card {
  border: 1px solid #67c23a;
  background-color: #f0f9ff;
}

.streaming-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-weight: 500;
  color: #67c23a;
}

.streaming-content {
  max-height: 300px;
  overflow-y: auto;
  padding: 12px;
  background-color: #ffffff;
  border-radius: 6px;
  border: 1px solid #e4e7ed;
}

.streaming-text {
  line-height: 1.8;
  font-size: 14px;
  
  white-space: pre-wrap;
  word-break: break-all;
}

.streaming-text-plain {
  margin: 0;
  line-height: 1.6;
  font-size: 13px;
  color: #606266;
  font-family: 'Courier New', monospace;
  white-space: pre-wrap;
  word-break: break-all;
}

.streaming-content::-webkit-scrollbar {
  width: 6px;
}

.streaming-content::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 3px;
}

.streaming-content::-webkit-scrollbar-thumb {
  background: #c1c1c1;
  border-radius: 3px;
}

.streaming-content::-webkit-scrollbar-thumb:hover {
  background: #a8a8a8;
}
.section-desc {
  margin: 0 0 12px 0;
  font-size: 13px;
  color: #909399;
  line-height: 1.4;
}

/* AI按钮组样式 */
.ai-button-group {
  display: flex;
  align-items: center;
}

/* 提示词对话框样式 */
.prompt-dialog-content {
  max-height: 600px;
  overflow-y: auto;
}

.prompt-list h4 {
  margin: 0 0 16px 0;
  
  font-size: 16px;
}

.prompt-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 12px;
  margin-bottom: 20px;
}

.prompt-card {
  border: 1px solid #e4e7ed;
  border-radius: 8px;
  padding: 12px;
  cursor: pointer;
  transition: all 0.3s;
  background-color: #ffffff;
}

.prompt-card:hover {
  border-color: #409eff;
  background-color: #f0f9ff;
  transform: translateY(-2px);
  box-shadow: 0 4px 8px rgba(64, 158, 255, 0.1);
}

.prompt-card.active {
  border-color: #409eff;
  background-color: #ecf5ff;
  box-shadow: 0 0 0 1px #409eff;
}

.prompt-card-header h5 {
  margin: 0 0 8px 0;
  font-size: 14px;
  
  font-weight: 600;
}

.prompt-card-description p {
  margin: 0 0 8px 0;
  font-size: 12px;
  color: #606266;
  line-height: 1.4;
}

.prompt-card-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.prompt-card-tags .el-tag {
  font-size: 11px;
  height: 20px;
  line-height: 18px;
}

.empty-prompts {
  text-align: center;
  padding: 40px 20px;
  color: #909399;
}

.prompt-variables {
  margin: 20px 0;
  padding: 16px;
  background-color: #f9f9f9;
  border-radius: 6px;
}

.prompt-variables h4 {
  margin: 0 0 16px 0;
  
  font-size: 14px;
}
.final-prompt {
  margin-top: 20px;
}
.final-prompt h4 {
  margin: 0 0 12px 0;
  
  font-size: 14px;
}
/* 章节生成对话框样式 */
.chapter-generate-content {
  max-height: 70vh;
  overflow: hidden;
}

.materials-section,
.prompt-section {
  height: 500px;
  overflow-y: auto;
}

.materials-section h4,
.prompt-section h4 {
  margin: 0 0 16px 0;
  
  font-size: 16px;
  font-weight: 600;
}


.materials-list {
  max-height: 200px;
  overflow-y: auto;
}



.material-info h5 {
  margin: 0 0 4px 0;
  font-size: 14px;
  
  font-weight: 600;
}

.material-info p {
  margin: 0;
  font-size: 12px;
  color: #606266;
  line-height: 1.4;
}

.material-tags,
.material-type {
  display: flex;
  gap: 4px;
}

/* 分类选择样式 */
.category-selection-card {
  margin-bottom: 16px;
}

.category-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.category-tab {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 8px 12px;
  border: 1px solid #e4e7ed;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.3s;
  background-color: #ffffff;
  min-width: 70px;
  text-align: center;
}

.category-tab:hover {
  border-color: #409eff;
  background-color: #f0f9ff;
}

.category-tab.active {
  border-color: #409eff;
  background-color: #ecf5ff;
  box-shadow: 0 0 0 1px #409eff;
}

.category-icon {
  font-size: 16px;
  margin-bottom: 4px;
}

.category-name {
  font-size: 11px;
  color: #606266;
  line-height: 1.2;
}
.category-tab.active .category-name {
  color: #409eff;
  font-weight: 600;
}
.prompt-card-small h5 {
  margin: 0 0 6px 0;
  font-size: 13px;
  
  font-weight: 600;
}

.prompt-card-small p {
  margin: 0 0 6px 0;
  font-size: 11px;
  color: #606266;
  line-height: 1.3;
}

.prompt-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.prompt-tags .el-tag {
  font-size: 10px;
  height: 18px;
  line-height: 16px;
}
.variables-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.dialog-footer {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}

/* 前文概要章节选择样式 */
.context-variable-container {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.context-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
}

.context-chapter-option {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 4px 0;
}

.context-chapter-option .chapter-title {
  font-size: 13px;
  
  font-weight: 500;
  flex: 1;
}

.context-chapter-option .chapter-meta {
  display: flex;
  align-items: center;
  gap: 8px;
}

.context-chapter-option .word-count {
  font-size: 11px;
  color: #909399;
}

/* 上下文标签页操作按钮 */
.context-tab-actions {
  display: flex;
  gap: 8px;
}

/* 批量生成角色对话框样式 */
.batch-generate-content {
  max-height: 70vh;
  overflow-y: auto;
}

.config-section,
.streaming-section,
.results-section {
  margin-bottom: 16px;
}

.character-type-options {
  display: flex;
  gap: 16px;
}

.streaming-content-container {
  max-height: 300px;
  overflow-y: auto;
  border: 1px solid #e4e7ed;
  border-radius: 6px;
  background-color: #fafafa;
}

.streaming-content {
  padding: 16px;
  font-family: 'Courier New', monospace;
  font-size: 14px;
  line-height: 1.6;
  
  white-space: pre-wrap;
}

.results-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.result-actions {
  display: flex;
  gap: 8px;
}

.generated-characters-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
  gap: 16px;
  max-height: 400px;
  overflow-y: auto;
}

.generated-character-card {
  border: 2px solid #e4e7ed;
  border-radius: 8px;
  padding: 16px;
  cursor: pointer;
  transition: all 0.3s;
  background-color: #ffffff;
}

.generated-character-card:hover {
  border-color: #409eff;
  background-color: #f0f9ff;
}

.generated-character-card.selected {
  border-color: #409eff;
  background-color: #ecf5ff;
  box-shadow: 0 0 0 1px #409eff;
}

.character-header {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 12px;
}

.character-avatar-preview {
  flex-shrink: 0;
}

.character-avatar-preview .default-avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  font-size: 16px;
}

.character-basic-info {
  flex: 1;
}

.character-basic-info h4 {
  margin: 0 0 8px 0;
  font-size: 16px;
  
  font-weight: 600;
}

.character-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.age-text {
  font-size: 12px;
  color: #909399;
}

.selection-indicator {
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.selected-icon {
  color: #409eff;
  font-size: 18px;
}

.character-details {
  border-top: 1px solid #f0f0f0;
  padding-top: 12px;
}

.detail-item {
  margin-bottom: 8px;
}

.detail-item label {
  font-size: 12px;
  color: #909399;
  font-weight: 600;
  margin-bottom: 4px;
  display: block;
}

.detail-item p {
  margin: 0;
  font-size: 13px;
  color: #606266;
  line-height: 1.4;
  max-height: 40px;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.character-tags-preview {
  margin-top: 8px;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.character-tags-preview .el-tag {
  font-size: 10px;
  height: 18px;
  line-height: 16px;
}

.character-actions,
.world-actions {
  display: flex;
  gap: 8px;
}
/* 世界观生成对话框样式 */
.world-generate-content {
  max-height: 70vh;
  overflow-y: auto;
}

.world-type-options {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  margin-top: 8px;
  align-items: center;
}

.world-type-options .el-checkbox {
  margin: 0;
  white-space: nowrap;
  min-width: fit-content;
}

.generated-settings-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-height: 400px;
  overflow-y: auto;
}

.generated-setting-card {
  border: 2px solid #e4e7ed;
  border-radius: 8px;
  padding: 16px;
  cursor: pointer;
  transition: all 0.3s;
  background-color: #ffffff;
}

.generated-setting-card:hover {
  border-color: #409eff;
  background-color: #f0f9ff;
}

.generated-setting-card.selected {
  border-color: #409eff;
  background-color: #ecf5ff;
  box-shadow: 0 0 0 1px #409eff;
}

.setting-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 12px;
}

.setting-basic-info {
  flex: 1;
}

.setting-basic-info h4 {
  margin: 0 0 8px 0;
  font-size: 16px;
  
  font-weight: 600;
}

.setting-content p {
  margin: 0;
  font-size: 14px;
  color: #606266;
  line-height: 1.6;
  max-height: 80px;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
}

/* 世界观设定编辑对话框中的流式显示样式 */
.streaming-status-card {
  margin-top: 16px;
  border: 1px solid #e4e7ed;
  border-radius: 6px;
  background-color: #fafafa;
}

.streaming-header {
  padding: 12px 16px;
  background-color: #f5f7fa;
  border-bottom: 1px solid #e4e7ed;
  border-radius: 6px 6px 0 0;
}

.streaming-title {
  font-weight: 600;
  
}

.streaming-content-display {
  padding: 16px;
  max-height: 200px;
  overflow-y: auto;
  font-family: 'Courier New', monospace;
  font-size: 13px;
  line-height: 1.6;
  
  white-space: pre-wrap;
}




.selected-prompt-info {
  color: #409eff;
  font-size: 12px;
  margin-left: 5px;
}

/* AI弹窗样式 */
.ai-single-chapter-content,
.ai-batch-chapter-content,
.ai-optimize-content {
  padding: 10px 0;
}

.optimize-input-card,
.optimize-result-card {
  height: 100%;
}

.optimized-content,
.empty-result {
  padding: 20px;
  text-align: center;
  color: #909399;
}

.optimized-content .el-textarea {
  height: 100%;
}

.streaming-content-area {
  margin-top: 20px;
  border: 1px solid #e4e7ed;
  border-radius: 6px;
  background-color: #fafafa;
}

.streaming-card {
  margin: 0;
  border: none;
  background: transparent;
}

.streaming-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  background-color: #f5f7fa;
  border-bottom: 1px solid #e4e7ed;
  border-radius: 6px 6px 0 0;
}

.streaming-content {
  padding: 16px;
  max-height: 300px;
  overflow-y: auto;
}

.streaming-text-plain {
  font-family: 'Courier New', monospace;
  font-size: 13px;
  line-height: 1.6;
  
  white-space: pre-wrap;
  margin: 0;
}

.streaming-text {
  font-size: 14px;
  line-height: 1.6;
  
  background-color: #ffffff;
  border: 1px solid #e4e7ed;
  border-radius: 6px;
  padding: 12px;
  font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
  white-space: pre-wrap;
  word-wrap: break-word;
  min-height: 100px;
}

/* 流式内容光标动画效果 */
.streaming-text::after {
  content: '▋';
  color: #409eff;
  animation: blink 1s infinite;
}

@keyframes blink {
  0%, 50% { opacity: 1; }
  51%, 100% { opacity: 0; }
}

/* 主编辑器流式内容区域特殊样式 */
.editor-panel .streaming-content-area {
  margin: 16px 0;
  border: 2px solid #409eff;
  border-radius: 8px;
  background: linear-gradient(135deg, #f0f8ff 0%, #e6f3ff 100%);
}

.editor-panel .streaming-card {
  background: transparent;
  border: none;
}

.editor-panel .streaming-header .streaming-title {
  color: #409eff;
  font-weight: 600;
}

/* 新续写对话框样式 */
.new-continue-container {
  height: 600px;
  max-height: 80vh;
}

.continue-config-card,
.continue-result-card {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.continue-config-card .el-card__body,
.continue-result-card .el-card__body {
  flex: 1;
  overflow-y: auto;
  padding: 16px;
}
.continue-direction {
  margin-bottom: 20px;
}

.continue-direction h4 {
  margin: 0 0 12px 0;
  font-size: 14px;
  color: var(--el-text-color-primary);
}

.continue-word-count {
  margin-bottom: 20px;
}
.continue-word-count h4 {
  margin: 0 0 12px 0;
  font-size: 14px;
  color: var(--el-text-color-primary);
}

.word-count-tips {
  margin-top: 8px;
  font-size: 12px;
  color: var(--el-text-color-secondary);
}

.current-content-preview {
  margin-bottom: 20px;
}

.current-content-preview h4 {
  margin: 0 0 12px 0;
  font-size: 14px;
  color: var(--el-text-color-primary);
}

/* 续写结果区域样式调整 */
.streaming-content-box,
.result-content {
  max-height: 400px;
  overflow-y: auto;
}

.empty-result {
  min-height: 300px;
}

/* 章节选择样式 */
.materials-list {
  max-height: 400px;
  overflow-y: auto;
}

.chapter-material-card {
  padding: 14px;
  border: 1px solid #e1e8ed;
  border-radius: 8px;
  margin-bottom: 10px;
  cursor: pointer;
  transition: all 0.2s ease;
  background: #fafbfc;
  min-height: 80px;
  position: relative;
}

.chapter-material-card:hover {
  border-color: #409eff;
  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.1);
}

.chapter-material-card.selected {
  border-color: #409eff;
  background-color: #e6f4ff;
}

.chapter-material-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 8px;
  min-height: 32px;
  gap: 8px;
}
.chapter-material-name {
  font-weight: 500;
  
  font-size: 14px;
  flex: 1;
  margin-right: 8px;
  line-height: 1.4;
  word-wrap: break-word;
  overflow-wrap: break-word;
  min-width: 0;
}

.chapter-material-tags {
  display: flex;
  gap: 4px;
  flex-shrink: 0;
  flex-wrap: wrap;
  align-items: flex-start;
}

.chapter-material-desc {
  color: #666;
  font-size: 12px;
  line-height: 1.4;
  margin: 4px 0;
  word-wrap: break-word;
  overflow-wrap: break-word;
}

.chapter-material-content {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid #eee;
}

.content-preview {
  color: #999;
  font-size: 11px;
  line-height: 1.3;
  font-style: italic;
  word-wrap: break-word;
  overflow-wrap: break-word;
  display: block;
  margin-top: 4px;
}

/* 批量生成章节自定义提示词状态样式 */
.custom-prompt-status {
  margin: 16px 0;
}

.custom-prompt-status .el-alert {
  border-radius: 8px;
}

.prompt-preview {
  margin-top: 8px;
  font-size: 13px;
  color: #67c23a;
  line-height: 1.4;
  opacity: 0.9;
}

/* 提示词内容预览样式 */
.prompt-content-collapse {
  margin-top: 12px;
  border: 1px solid #e1f5fe;
  border-radius: 6px;
  background-color: #f8fdff;
}

.prompt-content-preview {
  padding: 0;
}

.prompt-content-header {
  margin-bottom: 8px;
  padding-bottom: 6px;
  border-bottom: 1px solid #e8f4fd;
}

.content-label {
  font-size: 13px;
  font-weight: 600;
  color: #409eff;
}
.prompt-content-text {
  padding: 12px;
  background-color: #fafcff;
  border: 1px solid #e8f4fd;
  border-radius: 4px;
  font-family: 'Courier New', Consolas, monospace;
  font-size: 12px;
  line-height: 1.6;
  color: #606266;
  white-space: pre-wrap;
  word-wrap: break-word;
  max-height: 200px;
  overflow-y: auto;
  margin-bottom: 16px;
}
.final-prompt-section {
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid #e8f4fd;
}
.final-prompt {
  background-color: #f0f9ff;
  border-color: #b3e5fc;
  color: #01579b;
}

/* 大纲生成对话框样式 */
.outline-generate-content {
  min-height: 400px;
}

.chapter-info-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
}

.chapter-info-header h4 {
  margin: 0;
  font-size: 16px;
  
}

.chapter-stats {
  display: flex;
  gap: 16px;
}

.stat-item {
  font-size: 13px;
  color: #606266;
}

.section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
}

.section-header h4 {
  margin: 0;
  font-size: 16px;
  
}

.outline-content-card {
  min-height: 300px;
}

.generating-status {
  padding: 40px 20px;
  text-align: center;
}

.generating-indicator {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  color: #409eff;
}

.generating-indicator .el-icon {
  font-size: 24px;
}

.outline-content {
  padding: 16px;
}

.outline-text {
  font-size: 14px;
  line-height: 1.8;
  
  white-space: pre-wrap;
  word-wrap: break-word;
  background-color: #fafbfc;
  border: 1px solid #e4e7ed;
  border-radius: 6px;
  padding: 16px;
}

.outline-placeholder {
  padding: 40px 20px;
  text-align: center;
  color: #909399;
}
.outline-placeholder p {
  margin: 0;
  font-size: 14px;
}
/* 批量大纲生成对话框样式 */
.batch-outline-content {
  max-height: 600px;
  overflow-y: auto;
}

.config-options {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.chapter-preview-item {
  padding: 12px;
  border: 1px solid #e4e7ed;
  border-radius: 6px;
  margin-bottom: 8px;
}

.chapter-preview-item .chapter-info h5 {
  margin: 0 0 8px 0;
  font-size: 14px;
  
}

.chapter-preview-item .chapter-meta {
  display: flex;
  gap: 12px;
  font-size: 13px;
  color: #606266;
}
.no-chapters {
  text-align: center;
  padding: 40px 20px;
  color: #909399;
}

.no-chapters p {
  margin: 8px 0;
}

.hint {
  font-size: 12px;
  
}

.progress-content {
  padding: 16px;
}

.progress-text {
  margin-top: 12px;
  text-align: center;
  color: #606266;
  font-size: 14px;
}

.result-stats {
  display: flex;
  gap: 8px;
}

.results-list {
  max-height: 300px;
  overflow-y: auto;
}

.result-item {
  padding: 12px;
  border: 1px solid #e4e7ed;
  border-radius: 6px;
  margin-bottom: 8px;
}

.result-item.success {
  border-color: #67c23a;
  background-color: #f0f9ff;
}

.result-item.error {
  border-color: #f56c6c;
  background-color: #fef0f0;
}

.result-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}

.chapter-name {
  font-weight: 600;
  
}

.error-message {
  color: #f56c6c;
  font-size: 13px;
}

.result-content {
  color: #606266;
  font-size: 13px;
  line-height: 1.5;
}

.result-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
}

.select-actions {
  display: flex;
  gap: 8px;
}

.chapter-info {
  display: flex;
  align-items: center;
  gap: 8px;
}

.chapter-checkbox {
  margin-right: 4px;
}

.result-item.selected {
  border-color: #409eff;
  background-color: #e6f4ff;
}

.content-preview {
  margin-top: 8px;
}

.content-text {
  margin-bottom: 8px;
  white-space: pre-wrap;
}

.original-outline {
  padding: 8px;
  background-color: #f5f7fa;
  border-radius: 4px;
  border-left: 3px solid #e6a23c;
}

.original-outline-label {
  font-size: 12px;
  color: #e6a23c;
  font-weight: 600;
  margin-bottom: 4px;
}

.original-outline-text {
  font-size: 12px;
  color: #909399;
  white-space: pre-wrap;
}

/* 黑暗模式样式 */
html.dark .writer-container {
  background-color: #0f172a;
}

html.dark .title-bar {
  background: #1a2332;
  border-bottom-color: #414d63;
}

html.dark .novel-title {
  color: #e4e7ed;
}

html.dark .main-content {
  background-color: #0f172a;
}

html.dark .left-panel {
  background: #1a2332;
  border-right-color: #414d63;
}

html.dark .right-tabs-panel {
  background: #1a2332;
  border-left-color: #414d63;
}

html.dark .vertical-tab-item {
  color: #cfd3dc;
}

html.dark .vertical-tab-item.active {
  color: #409eff;
}

html.dark .editor-panel {
  background: #1a2332;
}

html.dark .editor-header {
  background: #1a2332;
  border-bottom-color: #414d63;
}

html.dark .chapter-title {
  color: #e4e7ed;
}

html.dark .chapter-meta {
  color: #8a8f99;
}

html.dark .word-count {
  color: #cfd3dc;
}

html.dark .editor-toolbar {
  background: #1a2332;
  border-bottom-color: #414d63;
}

html.dark .quill-editor {
  background: #1a2332;
  color: #e4e7ed;
}

html.dark .ql-editor {
  background: #1a2332;
  color: #e4e7ed;
}

html.dark .ql-editor.ql-blank::before {
  color: #6c757d;
}

html.dark .chapter-outline {
  background: rgba(255, 255, 255, 0.04);
  border-color: #414d63;
  color: #cfd3dc;
}

html.dark .empty-state {
  color: #8a8f99;
}

html.dark .no-chapters {
  color: #8a8f99;
}

html.dark .hint {
  color: #6c757d;
}

html.dark .chapter-preview-item {
  background: rgba(255, 255, 255, 0.04);
  border-color: #414d63;
}

html.dark .chapter-preview-item .chapter-info h5 {
  color: #e4e7ed;
}

html.dark .chapter-preview-item .chapter-meta {
  color: #8a8f99;
}
html.dark .chapter-name {
  color: #e4e7ed;
}

html.dark .result-item {
  background: #1a2332;
  border-color: #414d63;
}

html.dark .result-item.success {
  background-color: rgba(103, 194, 58, 0.1);
}

html.dark .result-item.error {
  background-color: rgba(245, 108, 108, 0.1);
}

html.dark .result-item.selected {
  background-color: rgba(64, 158, 255, 0.1);
}

html.dark .result-content {
  color: #cfd3dc;
}

html.dark .progress-text {
  color: #cfd3dc;
}

html.dark .original-outline {
  background-color: rgba(230, 162, 60, 0.1);
  border-left-color: #e6a23c;
}

html.dark .original-outline-text {
  color: #8a8f99;
}

html.dark .error-message {
  color: #f56c6c;
}
</style>